RSA

RSA

RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

RSA的算法涉及三个参数,n、e1、e2。其中,n是两个大质数p、q的积,n的二进制表示时所占用的位数,就是所谓的密钥长度。e1和e2是一对相关的值,e1可以任意取。

算法过程

一、产生密钥

  1. 为了产生两个密钥,选取两个大素数,p和q,为了获得最大程度的安全性,两数的长度一样。计算乘积

    n=p*q;

  2. 随机取加密密钥e,使得e 和(p-1)(q-1) 互素,最后采用扩展欧几里得算法计算解密密钥d,

    d=e^-1 mod (p-1)(q-1)
    
    注意

    d和n也是互素。e和n是公开密钥,d是私人密钥。

    RSA加解密的算法完全相同,设A为明文,B为密文,则:

    ​ A=B^d mod n;

    ​ B=A^e mod n;

    公钥加密体制中,一般用公钥加密,私钥解密

    e1和e2可以互换使用,即:

    ​ A=B^e mod n;

    ​ B=A^d mod n;

    我们可以设计出一对公私密钥,加密密钥(公钥)为:KU =(e,n)=(3,33),解密密钥(私钥)为:KR =(d,n)=(7,33)。

    二、英文数字化

    将明文信息数字化,并将每块两个数字分组。假定明文英文字母编码表为按字母顺序排列数值,即:

RSA-1521422884128.PNG

三、明文加密

**加密消息m时,首先将它分为比n小的数据分组(采用二级制数,选取小于n的2的最大次幂),也就是说,若果p和n为100位的素数,那么n将有200位,每个消息分组m应该小于200位长 **

用户加密密钥(3,33) 将数字化明文分组信息加密成密文。由C≡M^e(mod n)得:

RSA明文加密-1521422898913.PNG

四、密文解密

用户B收到密文,若将其解密,只需要计算 M≡c^d(mod n)

RSA解密.PNG

用户B得到明文信息为:11,05,25。根据上面的编码表将其转换为英文,我们又得到了恢复后的原文“key”

e值

最常用的三个e值:3, 17, 65537(2^16+1).

X.509中建议采用65537^[304], PEM中建议采用3[37],PKCS#1建议采用3或65537[1345].

PKCS#1填充

  • 在BouncyCastle实现RSA的PKCS1V1.5模式中,如果是公钥加密信息(forEncryption=true),密钥长度为1024位,那么输出的密文块长度为128个字节,输入的明文块长度为127-10,即输入的明文块最大是117位,如果输入的明文块小于117位,比如输入的明文块长度为64位,那么会对这个明文块进行补位,在明文块前添加一位的0x02字节(代表公钥加密)然后后面的52位为随机的字节,在补位的最后一位,{即52(117-64-1),从零开始的},添加一位的字节0x00,在补位的后面添加实际的明文块。这样做的目的就是使得明文块转化成与module差不多的大整数。
  • 如果是私钥加密(forPrivateKey=true),密钥长度为1024位,那么输出 的密文块长度也是128字节,输入的明文块的长度为127-10,即输入的明文块最大是117位,如果输入的明文块小于117位,比如输入的明文块长度为64位,那么对这个明文块进行补位,在明文块前添加一位的0x01字节(代表私钥加密),然后在后面的52位为字节0xff,在最后一位{即52(117-64-1),从零开始),添加一位的字节0x00,在补位的后面添加时间的明文块。

ECC

椭圆曲线加密算法

算法流程

ECC算法的加密过程:

  1. 小倩选定一条椭圆曲线Ep(a,b),并取椭圆曲线上一点,作为基点G。
  2. 小倩选择一个私有密钥k,并生成公开密钥K=kG。(这一步既是上文提到的打点过程)
  3. 小倩将Ep(a,b)和点K,G传给小高。
  4. 小高接到信息后,将待传输的明文编码到Ep(a,b)上一点M(编码方法很多,这里不作讨论),并产生一个随机整数r
  5. 小高计算点C1=M+rK;C2=rG。
  6. 小高将C1、C2传给小倩。
  7. 小倩接到信息后,计算C1-kC2,结果就是点M。因为 C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M

然后再对点M进行解码就可以得到明文。

在这个加密通信中,如果有一个偷窥者H ,他只能看到Ep(a,b)、K、G、C1、C2, 而通过K、G 求k 或通过C2、G求r 都是相对困难的,原因上文已经提到。

因此,H无法得到A、B间传送的明文信息。

/**
 * RSA algorithm.
 */
public static final String KEY_ALGORITHM = "RSA";

/**
 * digital signature algorithm
 */
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

/**
 * Gets public key.
 */
private static final String PUBLIC_KEY = "RSAPublicKey";

/**
 * Gets private key.
 */
private static final String PRIVATE_KEY = "RSAPrivateKey";

/**
 * RSA maximum encryption text size.
 */
private static final int MAX_ENCRYPT_BLOCK = 117;

/**
 * RSA maximum decryption text size.
 */
private static final int MAX_DECRYPT_BLOCK = 128;
    /**
     * <p>
     * Use the private key to generate digital signatures for the information.
     * </p>
     *
     * @param data
     *            Encrypted data
     * @param PrivateKey
     *            Private Key (BASE64 encoding)
     * @return Digit signature (BASE64 encoding)
     * @throws Exception
     */
    public byte[] sign(byte[] data, String privateKey) {
        try {
            byte[] keyBytes = Base64Utils.decode(privateKey);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory;
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(privateK);
            signature.update(data);
            return signature.sign();
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {

            e.printStackTrace();
        }

        return null;
    }

    /**
     * <p>
     * Verify digit signature.
     * </p>
     *
     * @param data
     *            Encrypted data
     * @param publicKey
     *            Public Key(BASE64 encoding)
     * @param sign
     *            Digit signature
     *
     * @return result from verify
     * @throws Exception
     *
     */
    public boolean verify(byte[] data, String publicKey, byte[] sign) {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicK = keyFactory.generatePublic(keySpec);

            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(publicK);
            signature.update(data);

            return signature.verify(sign);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    /**
     * <P>
     * Decrypted with the private key
     * </p>
     *
     * @param encryptedData
     *            Encrypted data
     * @param privateKey
     *            Private Key (BASE64 encoding)
     * @return decryptedData
     * @throws Exception
     */
    public byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) {
        byte[] keyBytes = Base64Utils.decode(privateKey);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateK);
            ByteArrayOutputStream out = new ByteArrayOutputStream();

            int inputLen = encryptedData.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;

            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }

            byte[] decryptedData = out.toByteArray();
            out.close();

            return decryptedData;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }
    
        /**
     * <p>
     * Encrypt with the public key.
     * </p>
     *
     * @param data
     *            Plain text
     * @param publicKey
     *            Public key(BASE64 encoding)
     * @return encryptedData
     * @throws Exception
     */
    public byte[] encryptByPublicKey(byte[] data, String publicKey) {

        byte[] keyBytes = Base64Utils.decode(publicKey);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory;
        try {
            keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicK);

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int inputLen = data.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;

            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }

                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }

            byte[] encryptedData = out.toByteArray();
            out.close();

            return encryptedData;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException | IllegalBlockSizeException
                | BadPaddingException | InvalidKeyException | NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 姓名:于川皓 学号:16140210089 转载自:https://baike.baidu.com/item/RS...
    道无涯_cc76阅读 2,532评论 0 1
  • 公钥密码系统及RSA公钥算法 本文简单介绍了公开密钥密码系统的思想和特点,并具体介绍了RSA算法的理论基础,工作原...
    火狼o阅读 4,272评论 2 15
  • 关于Quantum Algorithms for Computing Short Discrete Logarit...
    L_jun阅读 475评论 0 0
  • 心赏29,亲爱的婆婆,早上我起来你就把饭做好了,衣服也都洗好了,家务活都是你在做我都不好意思了,你每天都把衣服洗干...
    五度练字武琳阅读 121评论 0 1
  • 每天坐在202公交车上, 我总喜欢靠后靠左边。 望着窗外车水马龙, 忽闪而过熟悉的风景。 匆匆而过,似曾相识, 化...
    LYP探路者阅读 225评论 0 1