非對稱加密算法RSA

RSA公鑰加密算法是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一塊兒提出的。1987年首次公佈,當時他們三人都在麻省理工學院工做。RSA就是他們三人姓氏開頭字母拼在一塊兒組成的。java

RSA算法晚於DH算法,這五個字母全都是人名首字母.DH算法是第一個非對稱密碼體系.算法

RSA算法運算速度慢,不適宜加密大量數據.一種解決方案是,將RSA跟對稱加密方式混合使用,將數據使用對稱加密方式加密,對稱加密的密鑰使用RSA算法加密,由於密鑰很短,因此時間費不了太多.實際上,對稱加密方式惟一的弊端就是密鑰很差傳遞,對稱加密方式也很難破解.服務器

RSA的適用情景一:加密

(1)服務器生成一個公鑰和一個私鑰,把公鑰公開了.spa

(2)客戶端使用公鑰把數據進行加密,上交服務器.別人是無法理解加密後的數據的.code

(3)服務器使用私鑰將數據解密,查看用戶提交的數據.orm

這種情景下,公鑰像是一個信箱,每一個人均可以往這個信箱裏面放信,可是這個信箱裏面的信只有掌握信箱鑰匙的人才能開箱查看.htm

RSA適用情景二:對象

(1)皇上生成一個公鑰和一個密鑰,把公鑰公開了.blog

(2)皇上發佈了一封詔書,昭告天下.詔書右下角有兩串數字,第一串數字是一個隨機串,第二串數字是用私鑰加密第一串數字所得的結果.

(3)有人不相信這詔書是皇上寫的,就把第二串數字使用公鑰解密,解密以後發現跟第一串數字同樣,說明確實是皇上寫的,由於通常人沒有密鑰,也就無法加密那些可以用公鑰解密的數據.

這種情境下,公鑰用於解密,私鑰用於加密,這能夠用於發佈公告時,證實這個公告確實是某我的發的.至關於簽名.

實際上,簽名沒有必要特別長,通常狀況下,簽名是定長的,要想定長,可使用MessageDigest算法,如MD5和SHA系列.因此就有了多種簽名算法,如MD5withRSA等.

下面給出java庫中RSA的用法,這個程序包括六部分:公鑰加密解密,私鑰加密解密,私鑰簽名公鑰驗證.

public class RSA {
    /**
     * 定義加密方式
     */
    private final static String KEY_RSA = "RSA";
    /**
     * 定義簽名算法
     */
    private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
    static PrivateKey toPrivateKey(byte[] b)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 構造PKCS8EncodedKeySpec對象
        PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(b);
        // 指定的加密算法
        KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
        // 取私鑰對象
        return factory.generatePrivate(pkcs);
    }
    static PublicKey toPublicKey(byte[] b) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(b);
        KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
        return factory.generatePublic(keySpec);
    }
    // 用私鑰對data簽名
    public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
        Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
        signature.initSign(toPrivateKey(privateKey));
        signature.update(data);
        return signature.sign();
    }
    // 公鑰解密數據
    public static boolean verify(byte[] data, byte[] publicKey, byte[] sign)
            throws Exception {
        Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
        signature.initVerify(toPublicKey(publicKey));
        signature.update(data);
        return signature.verify(sign);
    }
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key)
            throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_RSA);
        cipher.init(Cipher.DECRYPT_MODE, toPrivateKey(key));
        return cipher.doFinal(data);
    }
    public static byte[] decryptByPublicKey(byte[] data, byte[] key)
            throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_RSA);
        cipher.init(Cipher.DECRYPT_MODE, toPublicKey(key));
        return cipher.doFinal(data);
    }
    public static byte[] encryptByPublicKey(byte[] data, byte[] key)
            throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, toPublicKey(key));
        return cipher.doFinal(data);
    }
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key)
            throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, toPrivateKey(key));
        return cipher.doFinal(data);

    }
    static String tos(byte[] b) {
        String ans = "";
        for (int i = 0; i < b.length; i++) {
            ans += String.format("%02X", b[i]);
        }
        return ans;
    }
    public static void main(String[] args) throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
        // generator.initialize(1024);//默認爲1024
        KeyPair keyPair = generator.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        System.out.println("公鑰:" + tos(publicKey.getEncoded()));
        System.out.println("私鑰:" + tos(privateKey.getEncoded()));
        byte[] data = "你好,世界!".getBytes();
        System.out.println("公鑰加密-------私鑰解密");
        byte[] enc = encryptByPublicKey(data, publicKey.getEncoded());
        byte[] dec = decryptByPrivateKey(enc, privateKey.getEncoded());
        System.out.println("加密前:" + tos(data));
        System.out.println("解密後:" + tos(dec));
        System.out.println("私鑰加密--------公鑰解密");
        enc = encryptByPrivateKey(data, privateKey.getEncoded());
        dec = decryptByPublicKey(enc, publicKey.getEncoded());
        System.out.println("加密前:" + tos(data));
        System.out.println("解密後:" + tos(dec));
        System.out.println("私鑰簽名--------公鑰驗證簽名");
        byte[] sign = sign(data, privateKey.getEncoded());
        boolean status = verify(data, publicKey.getEncoded(), sign);
        System.out.println("簽名:" + tos(sign));
        System.out.println("狀態:" + status);
    }
}
相關文章
相關標籤/搜索