JAVA加密系列(三)- 非對稱加密算法 RSA、DSA

JAVA加密系列(三)- 非對稱加密算法 RSA、DSA

非對稱加密算法需要兩個密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對數據進行加密,只有用對應的私鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。 非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將公鑰公開,需要向甲方發送信息的其他角色(乙方)使用該密鑰(甲方的公鑰)對機密信息進行加密後再發送給甲方;甲方再用自己私鑰對加密後的信息進行解密。甲方想要回復乙方時正好相反,使用乙方的公鑰對數據進行加密,同理,乙方使用自己的私鑰來進行解密。

算法介紹

常見算法

  • RSA 第一個能同時用於加密和數字簽名的算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰算法,從提出到現今的三十多年裏,經歷了各種攻擊的考驗,逐漸爲人們接受,截止2017年被普遍認爲是最優秀的公鑰方案之一。
  • DSA Elgamal和Schnorr數字簽名的一個變種,DSA數字簽名優於Elgamal數字簽名的地方在於它的簽名長度較短,並且某些可以破解Elgamal方案的攻擊不適用DSA數字簽名
  • ECC 橢圓曲線密碼編碼學,是目前已知的公鑰體制中,對每比特所提供加密強度最高的一種體制。在軟件註冊保護方面起到很大的作用,一般的序列號通常由該算法產生。
  • Elgamal 其基礎是DiffieˉHellman密鑰交換算法,應對中間人攻擊時非常脆弱。

RSA

X509EncodedKeySpec和PKCS8EncodedKeySpec分別對應值公鑰和私鑰的規範 想對算法編碼和規範有更多瞭解的可以更深入的學習,以下例子只展示最簡單的使用

public class RSAUtil {

    //必須16位  否則會報錯  偏移量
    private static String IV = "asdfgh1234567890";
    //鑰匙  必須16位
    private static String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCA6exxuVOdLvxb6u+Gf5FvZD6zGO1sqDbW7zBgga/8LVZBktaljn0OzCjQKbfe/AQgyh/nIVi1zFO1+FC9cGSiWPGo1uX9kY5Chm0MS8UhtNfO13sOD0U/47MMOduuQ3WP+EJ0wFRvpzyGAp0vKqfCj3Hyrtaf8o7CqTGoLV7G7QIDAQAB";
    private static String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIDp7HG5U50u/Fvq74Z/kW9kPrMY7WyoNtbvMGCBr/wtVkGS1qWOfQ7MKNApt978BCDKH+chWLXMU7X4UL1wZKJY8ajW5f2RjkKGbQxLxSG0187Xew4PRT/jsww5265DdY/4QnTAVG+nPIYCnS8qp8KPcfKu1p/yjsKpMagtXsbtAgMBAAECgYBXf+94BWWmg9TQgvdPYFkTtYQFRj8pCEgovTMl3gDYduFcItHEj6F8oMB3AkoGdSJMK0VaOT0gMG8FTWVoH9h9iSM5uu/wsqr7mFI13+18bGFNv0OotV4UNpvlXqSksoRmetZDtaDPhO9/6anD1zY8VrJMXzJfJXhNdGFArEjpwQJBAOBsvzNDy1w/QtLobDm+TSOVVNtoPMO5qddR5PRnRWtpKASY4dQDl/KPa1fDrNp3oGfqA5FPLrQCmd6502Mvmn0CQQCTDRgarAuH9UVgGDeR+E18lWBsZEM4mGHFi9aigeLEw0th8PqZpdrPJixSo4S2lKcopkkagljiYONLlVeznBkxAkEAvRvloZUm73x/GqmvSJkK90kGUDvtuB/i9gWUID5FSNU7W2RYJwdAKqyfjzzbktvq1qVijDdk61qlvgBoF9QtIQJAcIammVJqCIHxspUVgQfHE7yi6o7Wuaoxtx9JAVXvF65yMuJagdTe2YFWjW4/kg+y0nJcooJ4TdLiW+ZOFE0xIQJBAILYIuxY5OpAm8cMqLOtldczj4sFfZb7hhojcEm3+/0ezNhzhZWPMI6txFieDel40a/qdPr8EPZjc0uYKTtlKNc=";

    public static void main(String[] args) {
//        genKeyPair();
        //字符串編碼
        System.out.println("編碼結果:" + encrypt("hello word", PUBLIC_KEY));
        //字符串解碼
        System.out.println("編碼結果:" + decrypt("NEo+98UAvp0q69M1mxorD/zrL4QjhBGAFd2Wj2nGcsF8Txb9r8VnUvFqGUM7ZNwXZdcnzW/SZqbGc8rHT0mmtPGWMlzJV8jMAWUgOh9jozyablwWU8Uj4BItiderZSQTrD+3E+ZL5TkkQKwmNCmdaABmozpkUz4B893m3GzhpjQ=",PRIVATE_KEY));
    }

    /**
     * 隨機生成密鑰對
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator類用於生成公鑰和私鑰對,基於RSA算法生成對象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密鑰對生成器,密鑰大小爲96-1024位
            keyPairGen.initialize(1024);
            // 生成一個密鑰對,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私鑰
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 得到公鑰
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            // 得到公鑰字符串
            String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
            // 得到私鑰字符串
            String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
            // 打印公鑰和私鑰
            System.out.println("公匙:" + publicKeyString);
            System.out.println("私匙:" + privateKeyString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加密
     */
    public static String encrypt(String str, String publicKey) {
        try {
            byte[] bytes = str.getBytes();
            //獲得RSA公匙
            RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
            bytes = cipher.doFinal(bytes);
            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 解密
     */
    public static String decrypt(String str, String privateKey) {
        try {
            byte[] bytes = Base64.getDecoder().decode(str);
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
            bytes = cipher.doFinal(bytes);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
log
編碼結果:eZxSLJKOvj0Ee/Lg9cx61ppaKuWXSRxvDU1deLR0ll2x1GEW5WO8Q9B4rO4DxDWfCLqfdmunSs2YZkm8ZDBUYi0N6VV4mqoz2SjckJyVe3pjwh4DifdrjAoO+0aYPKMhlGLjMY4Iy5SmkuSmot2AjsKHBhoqGs8bPnZoT7S6iKY=
編碼結果:hello word

DSA

Digital Signature Algorithm 是Schnorr和ElGamal簽名算法的變種,被美國NIST作爲DSS(DigitalSignature Standard)。簡單的說,這是一種更高級的驗證方式,用作數字簽名。不單單隻有公鑰、私鑰,還有數字簽名。私鑰加密生成數字簽名,公鑰驗證數據及簽名。如果數據和簽名不匹配則認爲驗證失敗!也就是說傳輸中的數據可以不再加密,接收方獲得數據後,拿到公鑰與簽名比對數據是否有效!

public class DSAUtil {

    private static String PUBLIC_KEY = "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAMUKDkoben3PPK01uS7hXrxKSOgJpQxVigU7mkfQL87B5GtwUKWmdKM5nMC89avU/S3qTg95+dQKjgydYqe8Ej3SVzDwnGlkZzWGgUOgs0pQ8q/cJ++4eUETH3l4svsLzwDgKIoT3fDBUef3fZ95oWbe1pIIt8RN0KRFJw8U+r4A";
    private static String PRIVATE_KEY = "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUa38CMSvzE1kkWgLiBQDrKCavBEk=";

    public static void main(String[] args) {
        //隨機生成成對密鑰
        genKeyPair();

        String sign=sign("hello word", PRIVATE_KEY);

        System.out.println("數字簽名:" + sign);
        //字符串解碼
        System.out.println("數字簽名校驗:" + verify("hello word",sign,PUBLIC_KEY));
    }

    /**
     * 隨機生成密鑰對
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator類用於生成公鑰和私鑰對,基於DSA算法生成對象 可以使用RSA算法生成 成對出現就好
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
            // 初始化密鑰對生成器,密鑰大小爲96-1024位 可自定義隨機產生器 SecureRandom
            keyPairGen.initialize(1024);
            // 生成一個密鑰對,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私鑰
            DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();
            // 得到公鑰
            DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();
            // 得到公鑰字符串
            String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
            // 得到私鑰字符串
            String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
            // 打印公鑰和私鑰
            System.out.println("公匙:" + publicKeyString);
            System.out.println("私匙:" + privateKeyString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 用私鑰對信息生成數字簽名
     */
    public static String sign(String str, String privateKey) {
        try {
            byte[] bytes = str.getBytes();
            //獲得DSA公匙
            DSAPrivateKey keyFactory = (DSAPrivateKey) KeyFactory.getInstance("DSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes())));
            Signature signature=Signature.getInstance("DSA");
            signature.initSign(keyFactory);
            signature.update(bytes);
            return new String(Base64.getEncoder().encode(signature.sign()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 校驗數字簽名
     */
    public static boolean verify(String str, String sign,String publicKey) {
        try {
            byte[] bytes =Base64.getDecoder().decode(sign);
            DSAPublicKey keyFactory = (DSAPublicKey) KeyFactory.getInstance("DSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey.getBytes())));
            Signature signature=Signature.getInstance("DSA");
            signature.initVerify(keyFactory);
            signature.update(str.getBytes());
            return signature.verify(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
log
公匙:MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGANQY1Hf9XoQcFocGugqaEP6xPgxPsZ1C63Zs1WWg4Fk6CV8xuK78hgk+BhVit2/h97DWp7LyTDT4gVjCHLuV58TUmZyiupeo0FZrKqrAr+t3Der9+MmBDzfvkgPPIIZudhoqJcTpox8UNdJ4yyvgXxMN4DSoWJ4O28q0jBaxC/Mk=
私匙:MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUcsPeT/5R1AiwvTpJmzv5TQxq65Q=
數字簽名:MCwCFGB6J9g/R5su1o3TbZYMAcroY6YIAhQTtbtXUH47pGRDzMCu74eq0sOMCg==
數字簽名校驗:true

總結

非對稱性加密還有很多,RSA和DSA是比較常用和常見的加密方式,安全性來講兩者差不多,DSA只是一種算法,和RSA不同之處在於它不能用作加密和解密,也不能進行密鑰交換,只用於簽名,它比RSA要快很多,RSA啥都好,但是RSA算法的祕鑰很長,加密的計算量比較大,安全性較高,但是加密速度比較慢,所以RSA加密常用於少量的核心數據的加密。

源碼下載

GitHub,感興趣的點個星星

詳情文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章