RSA

RSA

RSA算法是第一個(gè)能同時(shí)用于加密和數(shù)字簽名的算法,也易于理解和操作。RSA是被研究得最廣泛的公鑰算法,從提出到現(xiàn)今的三十多年里,經(jīng)歷了各種攻擊的考驗(yàn),逐漸為人們接受,普遍認(rèn)為是目前最優(yōu)秀的公鑰方案之一。RSA公開(kāi)密鑰密碼體制。所謂的公開(kāi)密鑰密碼體制就是使用不同的加密密鑰與解密密鑰,是一種“由已知加密密鑰推導(dǎo)出解密密鑰在計(jì)算上是不可行的”密碼體制。

RSA的算法涉及三個(gè)參數(shù),n、e1、e2。其中,n是兩個(gè)大質(zhì)數(shù)p、q的積,n的二進(jìn)制表示時(shí)所占用的位數(shù),就是所謂的密鑰長(zhǎng)度。e1和e2是一對(duì)相關(guān)的值,e1可以任意取。

算法過(guò)程

一、產(chǎn)生密鑰

  1. 為了產(chǎn)生兩個(gè)密鑰,選取兩個(gè)大素?cái)?shù),p和q,為了獲得最大程度的安全性,兩數(shù)的長(zhǎng)度一樣。計(jì)算乘積

    n=p*q;

  2. 隨機(jī)取加密密鑰e,使得e 和(p-1)(q-1) 互素,最后采用擴(kuò)展歐幾里得算法計(jì)算解密密鑰d,

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

    d和n也是互素。e和n是公開(kāi)密鑰,d是私人密鑰。

    ?

    RSA加解密的算法完全相同,設(shè)A為明文,B為密文,則:

    ? A=B^d mod n;

    ? B=A^e mod n;

    公鑰加密體制中,一般用公鑰加密,私鑰解密

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

    ? A=B^e mod n;

    ? B=A^d mod n;

    ?

    我們可以設(shè)計(jì)出一對(duì)公私密鑰,加密密鑰(公鑰)為:KU =(e,n)=(3,33),解密密鑰(私鑰)為:KR =(d,n)=(7,33)。

    二、英文數(shù)字化

    將明文信息數(shù)字化,并將每塊兩個(gè)數(shù)字分組。假定明文英文字母編碼表為按字母順序排列數(shù)值,即:

RSA-1521422884128.PNG

三、明文加密

**加密消息m時(shí),首先將它分為比n小的數(shù)據(jù)分組(采用二級(jí)制數(shù),選取小于n的2的最大次冪),也就是說(shuō),若果p和n為100位的素?cái)?shù),那么n將有200位,每個(gè)消息分組m應(yīng)該小于200位長(zhǎng) **

用戶加密密鑰(3,33) 將數(shù)字化明文分組信息加密成密文。由C≡M^e(mod n)得:

RSA明文加密-1521422898913.PNG

四、密文解密

用戶B收到密文,若將其解密,只需要計(jì)算 M≡c^d(mod n)

RSA解密.PNG

用戶B得到明文信息為:11,05,25。根據(jù)上面的編碼表將其轉(zhuǎn)換為英文,我們又得到了恢復(fù)后的原文“key”

e值

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

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

PKCS#1填充

?

  • 在BouncyCastle實(shí)現(xiàn)RSA的PKCS1V1.5模式中,如果是公鑰加密信息(forEncryption=true),密鑰長(zhǎng)度為1024位,那么輸出的密文塊長(zhǎng)度為128個(gè)字節(jié),輸入的明文塊長(zhǎng)度為127-10,即輸入的明文塊最大是117位,如果輸入的明文塊小于117位,比如輸入的明文塊長(zhǎng)度為64位,那么會(huì)對(duì)這個(gè)明文塊進(jìn)行補(bǔ)位,在明文塊前添加一位的0x02字節(jié)(代表公鑰加密)然后后面的52位為隨機(jī)的字節(jié),在補(bǔ)位的最后一位,{即52(117-64-1),從零開(kāi)始的},添加一位的字節(jié)0x00,在補(bǔ)位的后面添加實(shí)際的明文塊。這樣做的目的就是使得明文塊轉(zhuǎn)化成與module差不多的大整數(shù)。
  • 如果是私鑰加密(forPrivateKey=true),密鑰長(zhǎng)度為1024位,那么輸出 的密文塊長(zhǎng)度也是128字節(jié),輸入的明文塊的長(zhǎng)度為127-10,即輸入的明文塊最大是117位,如果輸入的明文塊小于117位,比如輸入的明文塊長(zhǎng)度為64位,那么對(duì)這個(gè)明文塊進(jìn)行補(bǔ)位,在明文塊前添加一位的0x01字節(jié)(代表私鑰加密),然后在后面的52位為字節(jié)0xff,在最后一位{即52(117-64-1),從零開(kāi)始),添加一位的字節(jié)0x00,在補(bǔ)位的后面添加時(shí)間的明文塊。

ECC

橢圓曲線加密算法

算法流程

ECC算法的加密過(guò)程:

  1. 小倩選定一條橢圓曲線Ep(a,b),并取橢圓曲線上一點(diǎn),作為基點(diǎn)G。
  2. 小倩選擇一個(gè)私有密鑰k,并生成公開(kāi)密鑰K=kG。(這一步既是上文提到的打點(diǎn)過(guò)程)
  3. 小倩將Ep(a,b)和點(diǎn)K,G傳給小高。
  4. 小高接到信息后,將待傳輸?shù)拿魑木幋a到Ep(a,b)上一點(diǎn)M(編碼方法很多,這里不作討論),并產(chǎn)生一個(gè)隨機(jī)整數(shù)r
  5. 小高計(jì)算點(diǎn)C1=M+rK;C2=rG。
  6. 小高將C1、C2傳給小倩。
  7. 小倩接到信息后,計(jì)算C1-kC2,結(jié)果就是點(diǎn)M。因?yàn)?C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M

然后再對(duì)點(diǎn)M進(jìn)行解碼就可以得到明文。

在這個(gè)加密通信中,如果有一個(gè)偷窺者H ,他只能看到Ep(a,b)、K、G、C1、C2, 而通過(guò)K、G 求k 或通過(guò)C2、G求r 都是相對(duì)困難的,原因上文已經(jīng)提到。

因此,H無(wú)法得到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;

            // 對(duì)數(shù)據(jù)分段解密
            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);
            // 對(duì)數(shù)據(jù)加密
            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;

            // 對(duì)數(shù)據(jù)分段加密
            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;
    }

?

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 姓名:于川皓 學(xué)號(hào):16140210089 轉(zhuǎn)載自:https://baike.baidu.com/item/RS...
    道無(wú)涯_cc76閱讀 2,797評(píng)論 0 1
  • 公鑰密碼系統(tǒng)及RSA公鑰算法 本文簡(jiǎn)單介紹了公開(kāi)密鑰密碼系統(tǒng)的思想和特點(diǎn),并具體介紹了RSA算法的理論基礎(chǔ),工作原...
    火狼o閱讀 4,429評(píng)論 2 15
  • 關(guān)于Quantum Algorithms for Computing Short Discrete Logarit...
    L_jun閱讀 601評(píng)論 0 0
  • 心賞29,親愛(ài)的婆婆,早上我起來(lái)你就把飯做好了,衣服也都洗好了,家務(wù)活都是你在做我都不好意思了,你每天都把衣服洗干...
    五度練字武琳閱讀 139評(píng)論 0 1
  • 每天坐在202公交車上, 我總喜歡靠后靠左邊。 望著窗外車水馬龍, 忽閃而過(guò)熟悉的風(fēng)景。 匆匆而過(guò),似曾相識(shí), 化...
    LYP探路者閱讀 269評(píng)論 0 1

友情鏈接更多精彩內(nèi)容