Java Web項目RSA加密

来源:http://www.cnblogs.com/mstk/archive/2016/05/17/5502110.html
-Advertisement-
Play Games

最近做的一個項目,伺服器為Java,採用SSH框架,客戶端為Android和IOS。當用戶登錄時,從客戶端向伺服器提交用戶名和密碼。這就存在一個問題,如果數據包在網路上被其他人截取了,密碼就有可能泄露。 可以採用Base64對密碼編碼,但是Base64要進行解碼是很容易的事。 另一種方法是對密碼進行 ...


最近做的一個項目,伺服器為Java,採用SSH框架,客戶端為Android和IOS。當用戶登錄時,從客戶端向伺服器提交用戶名和密碼。這就存在一個問題,如果數據包在網路上被其他人截取了,密碼就有可能泄露。

可以採用Base64對密碼編碼,但是Base64要進行解碼是很容易的事。

另一種方法是對密碼進行MD5加密,MD5是不可逆的,只能加密不能解密。但是其他人截取了密碼的MD5字元串以後,可以原封不動的將MD5加密後的字元串提交給伺服器,伺服器肯定會判斷這是正確的密碼,這樣還是可以登錄進去。

解決的方法就只能採用加密演算法了。加密演算法分為對稱加密和非對稱加密。對稱加密演算法,加密和解密使用相同的密鑰,密鑰在網路傳輸的過程中有可能被截取,所以不是很安全。非對稱加密,使用公鑰加密,只能使用私鑰解密,公鑰是公開的,私鑰是不公開的。即使在傳遞的過程中,公鑰被其他人獲取了也無所謂,因為公鑰是用來加密的,只有私鑰才能解密,而私鑰是不會傳遞的,也就不可能被其他人獲取。

非對稱加密最常用的就是RSA演算法,RSA演算法是由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的,取了他們姓的第一個字母來命名。RSA演算法的原理就不講了。密鑰長度為768的RSA演算法有可能被破解,密鑰長度為1024的RSA演算法還沒有被破解,所以可以認為密鑰長度為1024的RSA演算法是比較安全的。但是RSA演算法的計算量大,一般只用於關鍵信息的加密,如密碼、對稱加密演算法的密鑰等。在我們的項目中,就使用RSA演算法對用戶密碼進行加密。具體的步驟如下:

1. 客戶端向伺服器申請密鑰;

2. 伺服器接收到客戶端的申請以後,生成一對密鑰,將公鑰發給客戶端,私鑰自己保存;

3. 客戶端接收到公鑰以後,使用公鑰對密碼加密,然後將密文發給伺服器;

4. 伺服器接收到密文以後,使用私鑰解密,判斷是否是正確的密碼。

下麵是關鍵代碼。

生成密鑰和加密、解密的代碼:

/** 
     * 生成公鑰和私鑰 
     * @throws NoSuchAlgorithmException  
     * 
     */  
    public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException{  
        HashMap<String, Object> map = new HashMap<String, Object>();  
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
        keyPairGen.initialize(1024);  
        KeyPair keyPair = keyPairGen.generateKeyPair();  
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
        map.put("public", publicKey);  
        map.put("private", privateKey);  
        return map;  
    } 
    
    /** 
     * 使用模和指數生成RSA公鑰 
     * 註意:【此代碼用了預設補位方式,為RSA/None/PKCS1Padding,不同JDK預設的補位方式可能不同,如Android預設是RSA 
     * /None/NoPadding】 
     *  
     * @param modulus 
     *            模 
     * @param exponent 
     *            指數 
     * @return 
     */  
    public static RSAPublicKey getPublicKey(String modulus, String exponent) {  
        try {  
            BigInteger b1 = new BigInteger(modulus);  
            BigInteger b2 = new BigInteger(exponent);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);  
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
  
    /** 
     * 使用模和指數生成RSA私鑰 
     * 註意:【此代碼用了預設補位方式,為RSA/None/PKCS1Padding,不同JDK預設的補位方式可能不同,如Android預設是RSA 
     * /None/NoPadding】 
     *  
     * @param modulus 
     *            模 
     * @param exponent 
     *            指數 
     * @return 
     */  
    public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {  
        try {  
            BigInteger b1 = new BigInteger(modulus);  
            BigInteger b2 = new BigInteger(exponent);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);  
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
  
    /** 
     * 公鑰加密 
     *  
     * @param data 
     * @param publicKey 
     * @return 
     * @throws Exception 
     */  
    public static String encryptByPublicKey(String data, RSAPublicKey publicKey)  
            throws Exception {  
        Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");  
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
        // 模長  
        int key_len = publicKey.getModulus().bitLength() / 8;  
        // 加密數據長度 <= 模長-11  
        String[] datas = splitString(data, key_len - 11);  
        String mi = "";  
        //如果明文長度大於模長-11則要分組加密  
        for (String s : datas) {  
            mi += bcd2Str(cipher.doFinal(s.getBytes()));  
        }  
        return mi;  
    }  
  
    /** 
     * 私鑰解密 
     *  
     * @param data 
     * @param privateKey 
     * @return 
     * @throws Exception 
     */  
    public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)  
            throws Exception {  
        Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");  
        cipher.init(Cipher.DECRYPT_MODE, privateKey);  
        //模長  
        int key_len = privateKey.getModulus().bitLength() / 8;  
        byte[] bytes = data.getBytes();  
        byte[] bcd = ASCII_To_BCD(bytes, bytes.length);  
        System.err.println(bcd.length);  
        //如果密文長度大於模長則要分組解密  
        String ming = "";  
        byte[][] arrays = splitArray(bcd, key_len);  
        for(byte[] arr : arrays){  
            ming += new String(cipher.doFinal(arr));  
        }  
        return ming;  
    } 

伺服器收到客戶端的請求時,生成一對密鑰:

                HashMap<String, Object> mymap = RSAUtils.getKeys();
                // 生成公鑰和私鑰  
                RSAPublicKey publicKey = (RSAPublicKey) mymap.get("public");  
                RSAPrivateKey privateKey = (RSAPrivateKey) mymap.get("private"); 
                //
                String modulus = publicKey.getModulus().toString();  
                // 公鑰指數  
                String public_exponent = publicKey.getPublicExponent().toString();  
                // 私鑰指數  
                String private_exponent = privateKey.getPrivateExponent().toString(); 
                // 使用模和指數生成公鑰和私鑰  
                RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);  
                RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent);

將其中的模和私鑰指數發給客戶端,客戶端收到以後,使用getPublicKey(String modulus, String exponent)生成公鑰,使用公鑰對密碼加密,然後發給伺服器。伺服器收到密文以後,使用decryptByPrivateKey(String data, RSAPrivateKey privateKey)解密,獲得密碼明文,然後就可以判斷密碼是否正確。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在網上找到的資料比較零散,這部分學起來感覺也有點空虛,內容就只包括隱藏鍵盤和鍵盤高度兩部分 隱藏鍵盤其實就在我學習iOS開發的第一個程式裡面已經實踐過了,不過當時還懵懵懂懂,現在就瞭解了是什麼一回事,就記錄一下,也額外加點內容上去。 說這個鍵盤的出現和隱藏是和輸入框獲取和失去焦點有關係,輸入框獲取了 ...
  • 我不喜歡那些泛泛而談的去講那些形而上學的道理,更不喜歡記那些既定的東西。靠記憶去彌補思考的人,容易陷入人云亦云的境地,最後必定被記憶所圍困,而最終消亡的是創造力。希望這個高手之路系列能夠記錄我學習安卓的點點滴滴。從而匯成流,聚為江,成為海。 下麵就結合代碼分析一下ClassLoader這個東西。 安 ...
  • OC NSFileManager(文件路徑操作) 初始化 獲取當前目錄 更改當前目錄 創建新目錄 拷貝目錄(文件) 移動目錄(文件) 刪除目錄(文件 通過遞歸枚舉目錄下所有文件及目錄 獲取當前目錄下的文件及目錄 創建文件 判斷文件是否存在 獲取文件屬性 從文件讀二進位流 ` ` ...
  • 前言:對Rx不瞭解的朋友可以先看我的第一篇博文 RxJava 和 RxAndroid ,是對Rxjava的基本介紹 1、merge操作符,合併觀察對象 運行結果 ...
  • LoginViewController * loginVC = [[LoginViewController alloc]init]; 找window的三種方式 1、// UIWindow * window = [UIApplication sharedApplication].delegate.wi ...
  • 1. 避免界面在處理耗時(讀取資料庫,網路請求)操作時卡死,在另外一條線程中處理這些操作,然後在主線程中更新UI。代碼比NSThread NSOperation簡潔很多,而且GCD會自動根據任務在多核處理器上分配資源,優化程式。 dispatch_async(dispatch_get_global_ ...
  • UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight-64)]; webView.backgroundColor=YYCToothWashViewBgCol ...
  • 通過這張圖,我們可以知道一個MediaPlayer對象有以下的狀態:1)當一個MediaPlayer對象被剛剛用new操作符創建或是調用了reset()方法後,它就處於Idle狀態。當調用了release()方法後,它就處於End狀態。這兩種狀態之間是MediaPlayer對象的生命周期。1.1) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...