RSA 加解密 签名 示例

时间:2023-01-18 21:24:44
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
/**
 * RSA非对称加密算法。用法:1 公钥加密,私钥解密;2 私钥签名,公钥验证签名。
 */
public class RSAUtils {
    /** 指定加密算法为RSA */
    public static final String ALGORITHM = "RSA";
    /** 签名算法 */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    /** 指定key的大小*/
    public static final int KEYSIZE = 1024;
    /** 加密时支持的最大字节数为【证书位数/8 -11】,1024位的证书加密时最大支持117个字节,2048位的证书加密时最大支持245个字节*/
    public static final int MAX_ENCRYPT_SIZE = KEYSIZE / 8 - 11 - 1;
    /** 解密是支持的最大字节数为【证书位数/8】,1024位的证书解密时最大支持128个字节,2048位的证书解密时最大支持256个字节*/
    public static final int MAX_DECRYPT_SIZE = KEYSIZE / 8;
    /** 指定公钥存放文件 */
    public static final String PUBLIC_KEY_FILE = "PublicKey";
    /** 指定私钥存放文件 */
    public static final String PRIVATE_KEY_FILE = "PrivateKey";
    /** 字符串编码 */
    public static final String CHARSET = "UTF-8";

    public static void main(String[] args) throws Exception {
        generateKeyPair();
        test1("1");
        String source = "一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九";//刚刚好117个字符
        test1(source);//证书位数为1024时,加密超过117个字符就会报异常:javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
        test2(source + "我可以超过117个字符");
        test3(source.getBytes(CHARSET));
    }

    private static void test1(String source) throws Exception {
        String cryptograph = encrypt(source);// 生成的密文
        String target = decrypt(cryptograph);// 解密密文
        System.out.println("加密前【" + source + "】\n加密后【" + cryptograph + "】\n解密后【" + target + "】\n");
    }
    private static void test2(String source) throws Exception {
        byte[] cryptograph = encrypt(source.getBytes(CHARSET));// 生成的密文
        String cryptographStr = Base64.getEncoder().encodeToString(cryptograph);//这里不能用new String()来还原字符串
        byte[] target = decrypt(cryptograph);// 解密密文
        System.out.println("加密前【" + source + "】\n加密后【" + cryptographStr + "】\n解密后【" + new String(target, CHARSET) + "】\n");
    }
    private static void test3(byte[] datas) throws Exception {
        byte[] signature = sign(datas);
        System.out.println("原始数据"+Arrays.toString(datas));
        System.out.println("签名数据"+Arrays.toString(signature));
        System.out.println("签名是否正确:" + verify(datas, signature));
    }
    //******************************************************************************************
    //                                                                              生成密钥
    //******************************************************************************************
    /**
     * 生成并持久化密钥对
     */
    public static void generateKeyPair() throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        kpg.initialize(KEYSIZE, sr);
        /** 生成密匙对 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = kp.getPublic();
        /** 得到私钥 */
        Key privateKey = kp.getPrivate();
        /** 用对象流将生成的密钥写入文件 */
        ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
        ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
        oos1.writeObject(publicKey);
        oos2.writeObject(privateKey);
        /** 清空缓存,关闭文件输出流 */
        oos1.close();
        oos2.close();
    }
    /**
     * 获取公钥
     */
    public static Key getPublicKey() throws Exception {
        /** 将文件中的公钥对象读出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE));
        Key key = (Key) ois.readObject();//直接从持久化对象中获取KEY
        ois.close();
        return key;
    }
    /**
     * 获取私钥
     */
    public static Key getPrivateKey() throws Exception {
        /** 将文件中的私钥对象读出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE));
        Key key = (Key) ois.readObject();
        ois.close();
        return key;
    }
    //******************************************************************************************
    //                                                                              加解密
    //******************************************************************************************
    /**
     * 加密
     */
    public static String encrypt(String source) throws Exception {
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());//加密模式
        /** 执行加密操作*/
        byte[] b1 = cipher.doFinal(source.getBytes(CHARSET));
        return Base64.getEncoder().encodeToString(b1);
    }
    /**
     * 解密
     */
    public static String decrypt(String cryptograph) throws Exception {
        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());//解密模式
        byte[] b1 = Base64.getDecoder().decode(cryptograph);
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b, CHARSET);
    }
    //******************************************************************************************
    //                                                                              分段加解密
    //******************************************************************************************
    /**
     * 分段加密
     */
    public static byte[] encrypt(byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance(getPublicKey().getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        for (int i = 0; inputLen - offSet > 0; offSet = i * MAX_ENCRYPT_SIZE) {
            byte[] cache;
            if (inputLen - offSet > MAX_ENCRYPT_SIZE) cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_SIZE);
            else cache = cipher.doFinal(data, offSet, inputLen - offSet);
            out.write(cache, 0, cache.length);
            ++i;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }
    /**
     * 分段解密
     */
    public static byte[] decrypt(byte[] encryptedData) throws Exception {
        Cipher cipher = Cipher.getInstance(getPrivateKey().getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        for (int i = 0; inputLen - offSet > 0; offSet = i * MAX_DECRYPT_SIZE) {
            byte[] cache;
            if (inputLen - offSet > MAX_DECRYPT_SIZE) cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_SIZE);
            else cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            out.write(cache, 0, cache.length);
            ++i;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }
    //******************************************************************************************
    //                                                                              签名
    //******************************************************************************************
    /** 
    * 用私钥对信息生成数字签名 
    */
    public static byte[] sign(byte[] data) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign((PrivateKey) getPrivateKey());
        signature.update(data);
        return signature.sign();
    }
    /** 
    * 用公钥校验数字签名 
    * @param data 已加密数据 
    * @param sign 数字签名 
    */
    public static boolean verify(byte[] data, byte[] sign) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify((PublicKey) getPublicKey());
        signature.update(data);
        return signature.verify(sign);
    }

}

测试结果

加密前【1】
加密后【GibdXMLtPXHgw2A0MtESRboqrmAApTpfPAODrcGkzTXgw+gbkdQWU9ICjpFye+w1muh5loatUxL2cDqBvM25UnPhXAkh9QZZfiCfHxGPGyH6Evk1Cw/Jns4usqyz8tv5/gf/AXogIktmrvV70yb/yRga49qDBfJGJ4zTJ3nOR4Q=】
解密后【1】

加密前【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九】
加密后【ckc7RKtnog1sFI/RmNZ9s3WRBYQ3wPxGSWE4uWDq27pwf4chvEYZv8J2UcSC7yuT1oTHFLqjnr6qW1X/k8SXZSfaqdUyYUgyr4YNE7D7nmt5bYxqFec0PMEOq73GVDeay1c+crXC+HEFGxSs97mo8j5uJG4oT6sDCA1PNdja9ss=】
解密后【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九】

加密前【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九我可以超过117个字符】
加密后【O9+kTPKFz311XIQcgoR/fVMp/qVJTjEgXbi5+f8ZhvE4/0NFlc2CYTqZu4XTdIeJEIfBvKUcntKV6z1mf5lkk/mWJoDV8HPkcBgvjATkmbtU5oD2kTEhECyvxKYsfsvC1ybj9iUzWnePm6CLLM2PCV4H2D+cMknn6cbnkapz0TxdjUk1uAlZLM7/hDqRkW/sv5CQIBd5lJqtY3ffFHX2jIw8m9DbMO/tL5nRSTTgrs+fmJQYjAZcik+KTui98SyVbNa7lx9jPN0ySl0ehgKIz2SiS7Pby4Ys3Opa2H/INpjWJY0gkIYg3t1JAhCk7FalG7ZpgXWy7fzc4RnNlYcN1A==】
解密后【一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九我可以超过117个字符】

原始数据[-28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99, -27, -115, -127, -28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, -28, -70, -108, -27, -123, -83, -28, -72, -125, -27, -123, -85, -28, -71, -99]
签名数据[105, -36, 107, -65, 87, -111, 93, -11, -68, 31, 0, 96, 41, -43, 9, -11, 102, 44, 24, 67, 118, -109, 75, -124, -77, -27, -43, -56, -111, -69, 99, 105, -71, -73, 111, 119, 84, -81, 104, -81, 35, -91, -81, 121, -5, -78, 74, 120, 41, 15, 16, -54, -42, -55, 72, 59, -54, -59, -38, -62, 49, 112, -105, 102, -78, -91, 102, -83, 65, -50, -95, -44, 20, -34, -105, -62, 100, -103, -88, -11, -24, 123, -34, -110, 80, 70, 74, -73, -119, -123, -126, -20, -61, 59, -35, -62, -35, 117, -115, -43, 19, 85, 74, 44, -15, -109, -9, -11, -113, 82, -10, 74, 38, 109, 87, 79, 97, 127, -56, 31, -9, -20, 11, 59, -64, -57, 13, -80]
签名是否正确:true

RSA 加解密 签名 示例的更多相关文章

  1. iOS RSA加解密签名和验证

    转自:http://www.jianshu.com/p/81b0b54436b8 Pre:在公司负责了一个项目,需要用到iOS RSA验证签名的功能.后台给我的仅仅是一个公钥的字符串.经过起初的一段时 ...

  2. 调用OpenSSL实现RSA加解密和签名操作

    调用OpenSSL实现RSA加解密和签名操作 RSA公钥可以从证书和公钥文件,RSA私钥可以从私钥文件中提取.OpenSSL使用了一种BIO抽象IO机制读写所用文件,可以打开文件相关联的BIO,通过B ...

  3. RSA加解密用途简介及java示例

    在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...

  4. PHP RSA加解密示例(转)

    1.生成密钥和公钥 开始前需要准备openssl环境 linux 需要安装openssl工具包,传送门http://www.openssl.org/source/ window 下需要安装openss ...

  5. iOS使用Security.framework进行RSA 加密解密签名和验证签名

    iOS 上 Security.framework为我们提供了安全方面相关的api: Security框架提供的RSA在iOS上使用的一些小结 支持的RSA keySize 大小有:512,768,10 ...

  6. 【go语言】RSA加解密

    关于go语言的RSA加解密的介绍,这里有一篇文章,已经介绍的很完整了. 对应的go语言的加解密代码,参考git. 因为原文跨语言是跟php,我这里要跟c语言进行交互,所以,这里贴上c语言的例子. 参考 ...

  7. java RSA加解密以及用途

    在公司当前版本的中间件通信框架中,为了防止非授权第三方和到期客户端的连接,我们通过AES和RSA两种方式的加解密策略进行认证.对于非对称RSA加解密,因为其性能耗费较大,一般仅用于认证连接,不会用于每 ...

  8. 与非java语言使用RSA加解密遇到的问题:algid parse error, not a sequence

    遇到的问题 在一个与Ruby语言对接的项目中,决定使用RSA算法来作为数据传输的加密与签名算法.但是,在使用Ruby生成后给我的私钥时,却发生了异常:IOException: algid parse ...

  9. RSA加解密-2

    Java使用RSA加密解密签名及校验   package com.ihep; import java.io.BufferedReader; import java.io.BufferedWriter; ...

随机推荐

  1. haproxy实现自定义错误页面的内容

    现在利用haproxy实现自定义的haproxy的错误页面 我们现在实现自定义错误页面有以下的方法: 一种是自定义错误页面 haproxy.conf defaults errorfile 404 /e ...

  2. Linux free字段解析

    下面是free的运行结果,一共有4行.为了方便说明,我加上了列号.这样可以把free的输出看成一个二维数组FO(Free Output).例如: FO[2][1] = 24677460 FO[3][2 ...

  3. butterknife简化android开发

    butterknife库非常不错的依赖注入库 使用1  使用2 http://jakewharton.github.io/butterknife/ maven引入 http://www.mvnrepo ...

  4. January 22nd, 2018 Week 04th Monday

    It is only when you are pursued that you become swift. 唯有在被追赶的时候,你才能真正地奔跑. It is so bad a feeling wh ...

  5. 【题解】 [HNOI/AHOI2018]道路 (动态规划)

    懒得复制,戳我戳我 Solution: \(dp[i][j][k]\)以\(i\)为子树根节点,到根节点中有\(j\)条公路没修,\(k\)条铁路没修,存子树不便利和 \(dp[i][j][k]=mi ...

  6. Spring----有关bean的配置

    1.单例类的配置如果我们想创建一个单例类的bean,只能会通过静态工厂来创建.下图为一个单例类: Stage并没有提供公开的构造方法,构造方法都是私有的,必须通过getInstance()方法获得已经 ...

  7. Linux 去重 先sort再uniq

    从uniq命令的帮助信息中可以看到,该命令只过滤相邻的重复行. 如果要去掉所有重复行,需要先排序,或者使用uniq -u $ uniq --h Usage: uniq [OPTION]... [INP ...

  8. WebService简单实现

    1. WebService SOAP.WSDL.UDDISOAP(Simple Object Access Protocal,简单对象访问协议),是在分散或在分布式环境中交换信息的简单协议.WSDL( ...

  9. How to use Variables in different component

    1. In Script Task component Set Value: Dts.Variables["ErrorMsg"].Value = string.Format(&qu ...

  10. Spring深入学习

    涨知识系列 Environment environment = context.getEnvironment(); 在Spring中所有被加载到spring中的配置文件都会出现在这个环境变量中, 其中 ...