RSA —— 典型非对称加密算法

Wesley13
• 阅读 807

RSA —— 典型非对称加密算法

RSA —— JAVA代码

二话不说,先把代码实现再学习原理!

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author : R&M www.rmworking.com/blog
 *         2019/8/17 22:09
 *         demo
 *         org.security.utils
 */
public class RSAUtil {

    public static void main(String[] args) throws Exception {
        // 需要加密的数据
        String str = "qnloft.com(青柠Loft)";

        // keySize 推荐使用2046,必须使用1024以上大小,因为512已经被破解。
        RSAUtil rsa = new RSAUtil(1024);
        System.out.println("-------------  生成密匙对 (见图1) ---------------");
        String publicKey = rsa.getPublicKeyString();
        String privateKey = rsa.getPrivateKeyString();
        System.out.println(publicKey);
        System.out.println(privateKey);

        System.out.println("--------------  加解密数据 (见图2)  ---------------");
        // 私匙加密数据
        byte[] encryptRes1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);
        System.out.println("私匙加密结果是:" + encodeBase64(encryptRes1));
        // 公匙解密数据
        byte[] decryptRes1 = RSAUtil.decryptByPublicKey(encryptRes1, publicKey);
        assert decryptRes1 != null;
        System.out.println("公匙解密结果是:" + new String(decryptRes1));

        System.out.println("--------------  加解密数据 (见图3)  ---------------");
        // 公匙加密数据
        byte[] encryptRes2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);
        System.out.println("公匙加密结果是:" + encodeBase64(encryptRes2));
        // 私匙解密数据
        byte[] decryptRes2 = RSAUtil.decryptByPrivateKey(encryptRes2, privateKey);
        assert decryptRes2 != null;
        System.out.println("私匙解密结果是:" + new String(decryptRes2));
    }

    //非对称密钥算法
    private static final String KEY_ALGORITHM = "RSA";

    private KeyPair keyPair = null;

    public RSAUtil(int keySize) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(keySize);
        keyPair = keyPairGen.generateKeyPair();
    }


    // ------------------ 生成密匙 -----------------------

    /**
     * 获取私匙 byte[]
     *
     * @return
     */
    public byte[] getPrivateKey() {
        Key key = keyPair.getPrivate();
        return key.getEncoded();
    }

    /**
     * 获取公匙
     *
     * @return
     * @throws Exception
     */
    public byte[] getPublicKey() throws Exception {
        Key key = keyPair.getPublic();
        return key.getEncoded();
    }

    /**
     * 获取私匙 String
     *
     * @return
     */
    public String getPrivateKeyString() {
        return encodeBase64(this.getPrivateKey());
    }

    /**
     * 获取公匙
     *
     * @return
     * @throws Exception
     */
    public String getPublicKeyString() throws Exception {
        return encodeBase64(this.getPublicKey());
    }

    // ------------------ 加密 ---------------------------

    /**
     * 私匙加密
     *
     * @param data 需要加密的数据
     * @param key  私匙
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, Object key) throws Exception {
        return byPrivateKey(data, key, Cipher.ENCRYPT_MODE);
    }

    /**
     * 公匙加密
     *
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, Object key) throws Exception {
        return byPublicKey(data, key, Cipher.ENCRYPT_MODE);
    }

    // ------------------ 解密 ---------------------------

    /**
     * 公钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPublicKey(byte[] data, Object key) throws Exception {
        return byPublicKey(data, key, Cipher.DECRYPT_MODE);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return byte[] 解密数据
     */
    public static byte[] decryptByPrivateKey(byte[] data, Object key) throws Exception {
        return byPrivateKey(data, key, Cipher.DECRYPT_MODE);
    }

    public static byte[] byPublicKey(byte[] data, Object key, int cipherMode) throws Exception {
        if (data.length != 0 && key != null) {
            //实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            //初始化公钥
            //密钥材料转换
            X509EncodedKeySpec x509KeySpec = null;
            if (key instanceof String) {
                byte[] publicKey = decodeBase64(String.valueOf(key));
                x509KeySpec = new X509EncodedKeySpec(publicKey);
            } else if (key instanceof byte[]) {
                x509KeySpec = new X509EncodedKeySpec((byte[]) key);
            }
            //产生公钥
            PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
            //数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(cipherMode, pubKey);
            return cipher.doFinal(data);
        }
        return null;
    }

    private static byte[] byPrivateKey(byte[] data, Object key ,int cipherMode) throws Exception {
        if (data.length != 0 && key != null) {
            // 使用私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = null;
            if (key instanceof String) {
                byte[] privateKey = decodeBase64(String.valueOf(key));
                pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
            } else if (key instanceof byte[]) {
                pkcs8KeySpec = new PKCS8EncodedKeySpec((byte[]) key);
            }
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            // 生成私钥
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            // 加解密操作
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(cipherMode, privateKey);
            return cipher.doFinal(data);
        }
        return null;
    }

    public static String encodeBase64(byte[] binaryData) {
        return Base64.getEncoder().encodeToString(binaryData);
    }

    public static byte[] decodeBase64(String encoded) {
        return Base64.getDecoder().decode(encoded);
    }
}

RSA —— 加密过程图解

(图1)构建RSA算法密匙对

RSA —— 典型非对称加密算法

构建公钥和私钥,将私钥自己保存,然后将公钥发送给乙方。注意:密匙是一对形式存在的,必须一次生成公钥和私钥,以本次生成的密匙对进行数据加解密操作。

RSAUtil rsa = new RSAUtil(1024);
// publicKey 发送给乙方
String publicKey = rsa.getPublicKeyString();
// privateKey 自己留存
String privateKey = rsa.getPrivateKeyString();

(图2)甲方向乙方发送RSA加密数据

RSA —— 典型非对称加密算法

使用自己留存密匙对中的私钥进行数据加密操作,然后乙方会根据密匙对中的公匙进行数据解密。

// 私匙加密数据
byte[] encryptRes1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);
System.out.println("自己[甲方]私钥加密结果是:" + encodeBase64(encryptRes1));
// 公匙解密数据
byte[] decryptRes1 = RSAUtil.decryptByPublicKey(encryptRes1, publicKey);
assert decryptRes1 != null;
System.out.println("测试[乙方]公钥解密结果是:" + new String(decryptRes1));

(图3) 乙方向甲方发送RSA加密数据

RSA —— 典型非对称加密算法

当乙方向甲方发送加密数据时,可以使用密匙对中的公匙进行数据加密,甲方使用密匙对中的私钥进行数据解密操作。

// 公匙加密数据
byte[] encryptRes2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println("模拟[乙方]公钥加密,结果是:" + encodeBase64(encryptRes2));
// 私匙解密数据
byte[] decryptRes2 = RSAUtil.decryptByPrivateKey(encryptRes2, privateKey);
assert decryptRes2 != null;
System.out.println("自己[甲方]私钥解密,结果是:" + new String(decryptRes2));

RSA —— 简述

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

RSA底层的单向函数就死整数因式分解的问题:两个大素数相乘在计算是非常简单的,但是对其乘积结果做因式分解确实非常难的。
所以:对极大整数做因数分解的难度决定了RSA算法的可靠性,假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。
但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。

已公开的或已知的攻击方法编辑

  • 针对RSA最流行的攻击一般是基于大数因数分解。1999年,RSA-155 (512 bits)被成功分解,花了五个月时间(约8000 MIPS年)和224 CPU hours在一台有3.2G中央内存的Cray C916计算机上完成。

RSA-158表示如下:

39505874583265144526419767800614481996020776460304936454139376051579355626529450683609727842468219535093544305870490251995655335710209799226484977949442955603= 3388495837466721394368393204672181522815830368604993048084925840555281177×  11658823406671259903148376558383270818131012258146392600439520994131344334162924536139
  • 2009年12月12日,编号为RSA-768(768 bits, 232 digits)数也被成功分解。这一事件威胁了现通行的1024-bit密钥的安全性,普遍认为用户应尽快升级到2048-bit或以上

RSA-768表示如下:

1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413= 3347807169895689878604416984821269081770479498371376856891  2431388982883793878002287614711652531743087737814467999489×  3674604366679959042824463379962795263227915816434308764267  6032283815739666511279233373417143396810270092798736308917
  • 秀尔算法
    量子计算里的秀尔算法能使穷举的效率大大的提高。由于RSA算法是基于大数分解(无法抵抗穷举攻击),因此在未来量子计算能对RSA算法构成较大的威胁。一个拥有N量子比特的量子计算机,每次可进行2^N次运算,理论上讲,密钥为1024位长的RSA算法,用一台512量子比特位的量子计算机在1秒内即可破解。

RSA —— 数学公式

密匙对生成

RSA —— 典型非对称加密算法
RSA —— 典型非对称加密算法

加密与解密

RSA —— 典型非对称加密算法
RSA —— 典型非对称加密算法

参考文献

  • 《深入浅出密码学》
  • 《JAVA加密与解密的艺术--第2版》

--Posted from Rpc

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
前端尾随者 前端尾随者
2年前
sourceTree 添加 ssh key 方法
1.使用git客户的生成公私钥:id\rsa、id\rsa.pub1.1设置Git的username和email:$gitconfigglobaluser.name"xxx"$gitconfig\globaluser.email"xxx.mail@xxx.com"1.2.生成SSH密钥过程:1.2.1.检查是不是已经存在密钥(
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Git使用总结
生成密钥1.打开GitBash,运行  \_sshkeygen  \_2.密钥生成空间\_~/.ssh/id\_rsa  \_(C:/User/.ssh)3.输入密码(不输入增直接回车跳过)4._~/.ssh/id\_rsa.pub_ (公钥), _id\_rsa_ (私钥)下载代码到本地
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
JAVA_RSA_的加解密
RSA为非对称加密算法。数字签名的过程:1、对明文数据进行HASH加密,不可逆;2、对加密后的数据再用RSA的私钥进行二次加密。数字签名的验证过程:1、对明文数据进行HASH加密,不可逆;2、用RSA的公钥对数字签名后的数据进行解密;3、把1的结果和2的结果进行比较是否相等。RSA加密的过程和解密的过程都需要三步:加/解密、分组、填充。这三部分每
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这