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

JAVA开发 workingTime 120℃ 0评论

6fd316631c473160e94a73365e2485cf

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算法密匙对

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

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

(图2)甲方向乙方发送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加密数据

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

// 公匙加密数据
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 —— 数学公式

密匙对生成


加密与解密


参考文献

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

转载请注明:R&M » RSA —— 典型非对称加密算法

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

联系我:rm@rmworking.com