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. matlab操作之--读取指定文件夹下的“指定格式”文件

    %% 正负样本所在folder fext='*.png';%要读取的文件格式 positiveFolder='F:\课题\Crater detection\machingLearning\Positi ...

  2. Powerdesigner数据库建模--概念模型--ER图【转】

    转自http://www.cnblogs.com/dekevin/archive/2012/07/18/2596745.html Powerdesigner数据库建模--概念模型--ER图   目标: ...

  3. CMD 模块定义规范

    在 Sea.js 中,所有 JavaScript 模块都遵循 CMD(Common Module Definition) 模块定义规范.该规范明确了模块的基本书写格式和基本交互规则. 在 CMD 规范 ...

  4. 李洪强iOS开发之-环信01_iOS SDK 前的准备工作

    李洪强iOS开发之-环信01_iOS SDK 前的准备工作 1.1_注册环信开发者账号并创建后台应用 详细步骤:  注册并创建应用 注册环信开发者账号 第 1 步:在环信官网上点击“即时通讯云”,并点 ...

  5. SQL server 时间日期函数、类型转换

    一.日期与时间函数 二.子查询与分页查询

  6. Guava的一些总结

    guava是java API蛋糕上的冰激凌(精华). 源码包的简单说明:  com.google.common.annotations:普通注解类型.  com.google.common.base: ...

  7. 14.6.7 Configuring the Number of Background InnoDB IO Threads 配置InnoDB IO Threads的数量

    14.6.7 Configuring the Number of Background InnoDB IO Threads 配置InnoDB IO Threads的数量 InnoDB 使用后台线程来服 ...

  8. latch free

    latch free 等待事件: latch: cache buffers chains 这个等待事件其实还有另外一个重要的原因,那么就是逻辑读太高,SQL执行计划走错了导致的. 当进程想要获取锁存器 ...

  9. Bluetooth LE(低功耗蓝牙) - 第一部分

    前言 在写这篇文章的时候,谷歌刚刚发布了Android Wear ,摩托罗拉也发布了 Moto 360 智能手表.Android Wear的API还是相当基本的,是很好的文档材料,而且还会不断的更新, ...

  10. Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果

    1. 背景 在Java5的多线程中,可以使用Callable接口来实现具有返回值的线程.使用线程池的submit方法提交Callable任务,利用submit方法返回的Future存根,调用此存根的g ...