RSA詳解

RSA

RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操做。RSA是被研究得最普遍的公鑰算法,從提出到現今的三十多年裏,經歷了各類攻擊的考驗,逐漸爲人們接受,廣泛認爲是目前最優秀的公鑰方案之一。RSA公開密鑰密碼體制。所謂的公開密鑰密碼體制就是使用不一樣的加密密鑰與解密密鑰,是一種「由已知加密密鑰推導出解密密鑰在計算上是不可行的」密碼體制。java

RSA的算法涉及三個參數,n、e一、e2。其中,n是兩個大質數p、q的積,n的二進制表示時所佔用的位數,就是所謂的密鑰長度。e1和e2是一對相關的值,e1能夠任意取。git

算法過程

1、產生密鑰

  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;3d

    ​ B=A^e mod n;code

    公鑰加密體制中,通常用公鑰加密,私鑰解密orm

    e1和e2能夠互換使用,即:

    ​ A=B^e mod n;

    ​ B=A^d mod n;

    咱們能夠設計出一對公私密鑰,加密密鑰(公鑰)爲:KU =(e,n)=(3,33),解密密鑰(私鑰)爲:KR =(d,n)=(7,33)。

2、英文數字化

 將明文信息數字化,並將每塊兩個數字分組。假定明文英文字母編碼表爲按字母順序排列數值,即:

3、明文加密

加密消息m時,首先將它分爲比n小的數據分組(採用二級制數,選取小於n的2的最大次冪),也就是說,若果p和n爲100位的素數,那麼n將有200位,每一個消息分組m應該小於200位長

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

4、密文解密

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

 用戶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填充

RSA在應用中通常採用PKCS#1的標準進行填充

注意

  • 開頭爲00只爲了保證原文大小小於私鑰
  • 對於私鑰操做,你能夠把BT的值設爲01,這時PS填充的FF,那麼用00字節就能夠區分填充數據和明文數據對於公鑰操做,填充的都是非00字節,也可以用00字節區分開。若是你使用私鑰加密,建議你BT使用01,保證了安全性。
  • 對於BT爲02和01的,PS至少要有8個字節長,BT爲02確定是公鑰加密,01確定是私鑰加密,要保證PS至少有八個字節長 。由於EB= 00+BT+PS+00+D=k, 因此D<=k-11,因此當咱們使用128字節密鑰對數據進行加密時,明文數據的長度不能超過過128-11=117字節當RSA要加密數據大於 k-11字節時怎麼辦呢?把明文數據按照D的最大長度分塊而後逐塊加密,最後把密文拼起來就行。明文長度小於117ps處填充數據便可

附JAVA代碼

/**
 * 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;
    }
相關文章
相關標籤/搜索