Android 數(shù)據(jù)加密-RSA

RSA加密算法

1.RSA算法史:

RSA是1977年由羅納德·李維斯特(Ron Rivest)山上、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)三位數(shù)學家提出。在麻省理工學院工作搪缨。RSA就是他們?nèi)诵帐祥_頭字母拼在一起組成的碉哑。
但實際上挚币,在1973年,在英國政府通訊總部工作的數(shù)學家克利福德·柯克斯(Clifford Cocks)在一個內(nèi)部文件中提出了一個相同的算法扣典,但他的發(fā)現(xiàn)被列入機密妆毕,一直到1997年才被發(fā)表。

2.RSA加密簡介:

RSA加密是一種非對稱加密贮尖〉颜常可以在不直接傳遞密鑰的情況下,完成解密湿硝。這能夠確保信息的安全性薪前,避免了直接傳遞密鑰所造成的被破解的風險。是由一對密鑰來進行加解密的過程关斜,分別稱為公鑰和私鑰示括。兩者之間有數(shù)學相關,該加密算法的原理就是對一極大整數(shù)做因數(shù)分解的困難性來保證安全性痢畜。通常個人保存私鑰垛膝,公鑰是公開的(可能同時多人持有)

3.RSA加密、簽名區(qū)別:

加密和簽名都是為了安全性考慮丁稀,但略有不同吼拥。常有人問加密和簽名是用私鑰還是公鑰?其實都是對加密和簽名的作用有所混淆线衫。簡單的說凿可,加密是為了防止信息被泄露,而簽名是為了防止信息被篡改桶雀。這里舉2個例子說明矿酵。

4.使用場景

場景一:

第一個場景:戰(zhàn)場上唬复,B要給A傳遞一條消息,內(nèi)容為某一指令全肮。
RSA的加密過程如下:
@1A生成一對密鑰(公鑰和私鑰)敞咧,私鑰不公開,A自己保留辜腺。公鑰為公開的休建,任何人可以獲取。
@2A傳遞自己的公鑰給B评疗,B用A的公鑰對消息進行加密测砂。
@3A接收到B加密的消息,利用A自己的私鑰對消息進行解密百匆。
  在這個過程中砌些,只有2次傳遞過程,第一次是A傳遞公鑰給B加匈,第二次是B傳遞加密消息給A存璃,即使都被敵方截獲,也沒有危險性雕拼,因為只有A的私鑰才能對消息進行解密纵东,防止了消息內(nèi)容的泄露。

場景二:

第二個場景:A收到B發(fā)的消息后啥寇,需要進行回復“收到”偎球。
RSA簽名的過程如下:
(1)A生成一對密鑰(公鑰和私鑰),私鑰不公開辑甜,A自己保留衰絮。公鑰為公開的,任何人可以獲取磷醋。
(2)A用自己的私鑰對消息加簽岂傲,形成簽名,并將加簽的消息和消息本身一起傳遞給B子檀。
(3)B收到消息后,在獲取A的公鑰進行驗簽乃戈,如果驗簽出來的內(nèi)容與消息本身一致褂痰,證明消息是A回復的。
  在這個過程中症虑,只有2次傳遞過程缩歪,第一次是A傳遞加簽的消息和消息本身給B,第二次是B獲取A的公鑰谍憔,即使都被敵方截獲匪蝙,也沒有危險性主籍,因為只有A的私鑰才能對消息進行簽名,即使知道了消息內(nèi)容逛球,也無法偽造帶簽名的回復給B千元,防止了消息內(nèi)容的篡改。

項目案例:

第二個場景:A收到B發(fā)的消息后颤绕,需要進行回復“收到”幸海。
RSA簽名的過程如下:
(1)A生成一對密鑰(公鑰和私鑰),私鑰不公開奥务,A自己保留物独。公鑰為公開的,任何人可以獲取氯葬。
(2)A用自己的私鑰對消息加簽挡篓,形成簽名,并將加簽的消息和消息本身一起傳遞給B帚称。
(3)B收到消息后官研,在獲取A的公鑰進行驗簽,如果驗簽出來的內(nèi)容與消息本身一致世杀,證明消息是A回復的阀参。
  在這個過程中,只有2次傳遞過程瞻坝,第一次是A傳遞加簽的消息和消息本身給B蛛壳,第二次是B獲取A的公鑰,即使都被敵方截獲所刀,也沒有危險性衙荐,因為只有A的私鑰才能對消息進行簽名,即使知道了消息內(nèi)容浮创,也無法偽造帶簽名的回復給B忧吟,防止了消息內(nèi)容的篡改。

5.RSA項目中加密流程

RSA是一種常用的非對稱加密算法斩披,所謂非對稱加密是指使用一對密鑰(公鑰和私鑰)進行加密和解密溜族,公鑰人人都可以獲得,用于加密數(shù)據(jù)垦沉,私鑰保存在服務器中煌抒,用于解密數(shù)據(jù)。加密解密過程如下:


RSA加密流程.png

使用RSA進行加密解密厕倍,其優(yōu)點是非常不容易破解寡壮,缺點是和對稱加密(如AES)相比,加密速度較慢。因此况既,實際使用中这溅,常常將對稱加密和非對稱加密結(jié)合使用,即使用非對稱加密協(xié)商對稱加密的密鑰棒仍,使用對稱加密密鑰加密傳輸內(nèi)容悲靴。

6.RSA項目中加密源碼

6.1生成隨機公鑰私鑰

隨機生成公鑰和私鑰,用于測試RSA加密解密
 /**
     * 私鑰
     */
    private static RSAPrivateKey privateKey;
    /**
     * 公鑰
     */
    private static RSAPublicKey publicKey;

    /**
     * 隨機生成密鑰對
     */
    public static void genKeyPair() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        keyPairGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        privateKey = (RSAPrivateKey) keyPair.getPrivate();
        publicKey = (RSAPublicKey) keyPair.getPublic();
    }

6.2加載公鑰/私鑰

從字符串/文件輸入流中加載公鑰

    /**
     * 從字符串中加載公鑰
     *
     * @param publicKeyStr 公鑰數(shù)據(jù)字符串
     * @throws Exception 加載公鑰時產(chǎn)生的異常
     */
    public static void loadPublicKey(String publicKeyStr) throws Exception {
        try {
            byte[] buffer = EnDecryptionUtil.base64Decode(publicKeyStr);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("無此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公鑰非法");
        } catch (NullPointerException e) {
            throw new Exception("公鑰數(shù)據(jù)為空");
        }
    }
    /**
     * 從文件輸入流中加載公鑰
     *
     * @param in 公鑰輸入流
     * @throws Exception 加載公鑰時產(chǎn)生的異常
     */
    public static void loadPublicKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPublicKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("公鑰數(shù)據(jù)流讀取錯誤");
        } catch (NullPointerException e) {
            throw new Exception("公鑰輸入流為空");
        }
    }
//從字符串/文件輸入流中加載私鑰
    /**
     * 從字符串中加載私鑰
     * @param privateKeyStr
     * @throws Exception
     */
    public static void loadPrivateKey(String privateKeyStr) throws Exception {
        try {
            byte[] buffer = EnDecryptionUtil.base64Decode(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("無此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("私鑰非法");
        } catch (NullPointerException e) {
            throw new Exception("私鑰數(shù)據(jù)為空");
        }
    }
    /**
     * 從文件輸入流中加載私鑰
     *
     * @param in 私鑰輸入流
     * @return 是否成功
     * @throws Exception
     */
    public static void loadPrivateKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPrivateKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("私鑰數(shù)據(jù)讀取錯誤");
        } catch (NullPointerException e) {
            throw new Exception("私鑰輸入流為空");
        }
    }

6.3RSA加密數(shù)據(jù)

    /**
     * RSA加密過程
     *
     * @param publicKey     公鑰
     * @param plainTextData 明文數(shù)據(jù)
     * @return
     * @throws Exception 加密過程中的異常信息
     */
    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
        if (publicKey == null) {
            throw new Exception("加密公鑰為空, 請設置");
        }
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(plainTextData);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("無此加密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("加密公鑰非法,請檢查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文長度非法");
        } catch (BadPaddingException e) {
            throw new Exception("明文數(shù)據(jù)已損壞");
        }
    }
//加密后獲得的byte[]數(shù)組一般會進行Base64編碼

6.4RSA解密

    /**
     * RSA解密
     *
     * @param privateKey 私鑰
     * @param cipherData 密文數(shù)據(jù)
     * @return 明文
     * @throws Exception 解密過程中的異常信息
     */
    public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
        if (privateKey == null) {
            throw new Exception("解密私鑰為空, 請設置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(cipherData);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("無此解密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("解密私鑰非法,請檢查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("密文長度非法");
        } catch (BadPaddingException e) {
            throw new Exception("密文數(shù)據(jù)已損壞");
        }
    }
//如果輸入的密文進行過Base64編碼降狠,需Base64解碼后再進行RSA解密

6.4RSA 運行結(jié)果

公鑰:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO2TVhB1VIpUhNb5+owamkjmU8dNEMJyTbakBT
    b7GysKaA+byMRqJLRAbVPj+eD15erREOkv9A1z4mOMo7i+7hb6J8LuktCDWC5QeusvbwlpOjjIE6
    Sq8pETHPnHX5dd+ORFYWPrbd7drSIv0Fbm3R7zi0LhuJn3JWkLf1JEFDywIDAQAB
私鑰:MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAM7ZNWEHVUilSE1vn6jBqaSOZTx0
    0QwnJNtqQFNvsbKwpoD5vIxGoktEBtU+P54PXl6tEQ6S/0DXPiY4yjuL7uFvonwu6S0INYLlB66y
    9vCWk6OMgTpKrykRMc+cdfl1345EVhY+tt3t2tIi/QVubdHvOLQuG4mfclaQt/UkQUPLAgMBAAEC
    gYB+M3Xm4iN9dCI95JnDy4ymMp6/mQImaQeKuzPN9Dq1rCOaU0RfTYUdaL7GgfkshXHtT6g1fSgx
    NmHbzhBM7l5qoYJNwz/8KQ9rTphdc0JQFzu3ECkDZvOe+yjSKWpuZFGizLsB2j3Og4MF3fOKNfN7
    c1ucNNEYpzbGPyOPC23TWQJBAPOU5pLEwMV4VSC3LgJcjorvf5DQqJVpnPYyHRE7MFhsnVHfmbIq
    nTBhOcdomwOde+yQjerGIi7W7RIjobgoZdUCQQDZZOLEo5qdIXn319R3ucPsAHLPcTa8kfxpUHLo
    rN8INKUj7dR3FtWc9cye5fzWRg+NkBx6OC408l95qeGvBbMfAkEAqQJ7DgFJBHtfDcksOmVAXnSZ
    XcD6CFn0l/rjok4gWGpcqi9stGvPD3+WmJ8jV9nQ367ZWbpKg5eLfReOIXqeVQJBAMuxwuVbIoE+
    n8kBm1w/XHuig/EpdI9F/oszTSgE6soGggHjU6PuamMy0PLGLp0bcnFDadt/DpSf0aPu8L8NCSMC
    QQDvL5cjxQqIPJSP1T+JKktvd+nWPULt7Adir1fab022e0XfEod73Eoo4rp0GmN0hSZUH0VBBvqf
    lNY1P23tZP3C

待加密明文:123456
加密后Base64數(shù)據(jù):KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
    GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
    3kvBNDbYvDdfjMD/8JY=

待解密Base64密文:KMzWgXeWLpc31/D3LOv65AYquARkNCoPNVy+vqZd4ASC8hev1iZtBOowmWp5mMr0pYHya9AK6Ang
    GZmT2KzS472r+UR6LJxY7u3qthGuWiWcWmZbyH/z2LEB6du60b8BOpa670GE/HB074z85kPTWCWE
    3kvBNDbYvDdfjMD/8JY=
解密后數(shù)據(jù):123456

總結(jié):

公鑰加密对竣、私鑰解密、私鑰簽名榜配、公鑰驗簽否纬。

想要源碼評論區(qū)回復我,給你私發(fā)鏈接

Kotlin基礎篇【1】Android Studio 3.0 Kotlin環(huán)境配置
Kotlin基礎篇【2】初識Kotlin的意義
Kotlin基礎篇【3】Kotlin基礎語法

=======Kotlin基礎篇【4】Kotlin基礎語法即將更新=======

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛋褥,一起剝皮案震驚了整個濱河市临燃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烙心,老刑警劉巖膜廊,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異淫茵,居然都是意外死亡爪瓜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門匙瘪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铆铆,“玉大人,你說我怎么就攤上這事丹喻”』酰” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵碍论,是天一觀的道長谅猾。 經(jīng)常有香客問我,道長鳍悠,這世上最難降的妖魔是什么税娜? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮藏研,結(jié)果婚禮上巧涧,老公的妹妹穿的比我還像新娘。我一直安慰自己遥倦,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著袒哥,像睡著了一般缩筛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堡称,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天瞎抛,我揣著相機與錄音,去河邊找鬼却紧。 笑死桐臊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晓殊。 我是一名探鬼主播断凶,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼巫俺!你這毒婦竟也來了认烁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤介汹,失蹤者是張志新(化名)和其女友劉穎却嗡,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘹承,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡窗价,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叹卷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撼港。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖豪娜,靈堂內(nèi)的尸體忽然破棺而出餐胀,到底是詐尸還是另有隱情,我是刑警寧澤瘤载,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布否灾,位于F島的核電站,受9級特大地震影響鸣奔,放射性物質(zhì)發(fā)生泄漏墨技。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一挎狸、第九天 我趴在偏房一處隱蔽的房頂上張望扣汪。 院中可真熱鬧,春花似錦锨匆、人聲如沸崭别。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅主。三九已至舞痰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诀姚,已是汗流浹背响牛。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赫段,地道東北人呀打。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像糯笙,于是被迫代替她去往敵國和親贬丛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容