工做奇談——使用對稱密匙加密數據

一、對稱密匙及對稱加密算法DES簡介

         對稱密鑰加密,又稱私鑰加密,即信息的發送方和接收方用一個密鑰去加密和解密數據。它的最大優點是加/解密速度快,適合於對大數據量進行加密。javascript

         DES算法全稱爲Data Encryption Standard,即數據加密算法,它是IBM公司於1975年研究成功並公開發表的。DES算法的入口參數有三個:Key、Data、Mode。其中Key爲8個字節共64位,是DES算法的工做密鑰;Data也爲8個字節64位,是要被加密或被解密的數據;Mode爲DES的工做方式,有兩種:加密或解密。java

二、實現思路(防君子不防小人)

        項目裏有個活,要求登陸的時候帳號密碼加密傳輸,又不能使用SSL(真的坑),沒辦法,本身想了想,決定使用對稱密匙來加密解密數據。git

        可是密匙總不能是固定的吧,萬一別人拿到了個人密匙就能夠隨意破解數據了(由於加密算法是固定的),因此個人實現思路是在用戶訪問login頁面的時候,服務端生成一個40位(此算法的密匙必須是八的倍數)的隨機密匙給瀏覽器,而後寫一個JQ在瀏覽器同步加密用戶輸入的用戶名及密碼,當用戶提交表單的時候再將加密好的用戶名密碼及密匙傳到服務端解密出原始數據不就OK了?想到這裏說幹就幹!!!算法

三、代碼實現

    3.一、 加密及解密算法實現

            加密及解密算法的代碼我已經寫成一個工具類,不太懂的同窗能夠去百度,百度上一大堆  щ(゚Д゚щ) ,代碼以下:我也已經傳到碼雲上:https://git.oschina.net/LKWai數據庫

package cn.yy.util;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

/**
 * DES加解密工具類
 * 
 * @author 二十歲之後
 *
 * @date 2017年7月27日 
 */
public class DESUtil {
    private static final String DES_ALGORITHM = "DES";

    /**
     * DES加密
     * 
     * @param plainData 原始字符串
     * @param secretKey 加密密鑰
     * @return 加密後的字符串
     * @throws Exception
     */
    public static String encryption(String plainData, String secretKey) throws Exception {

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(DES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey));

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {

        }

        try {
            // 爲了防止解密時報javax.crypto.IllegalBlockSizeException: Input length must
            // be multiple of 8 when decrypting with padded cipher異常,
            // 不能把加密後的字節數組直接轉換成字符串
            byte[] buf = cipher.doFinal(plainData.getBytes());

            return Base64Utils.encode(buf);

        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            throw new Exception("IllegalBlockSizeException", e);
        } catch (BadPaddingException e) {
            e.printStackTrace();
            throw new Exception("BadPaddingException", e);
        }

    }


    /**
     * DES解密
     * @param secretData 密碼字符串
     * @param secretKey 解密密鑰
     * @return 原始字符串
     * @throws Exception
     */
    public static String decryption(String secretData, String secretKey) throws Exception {

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(DES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey));

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new Exception("NoSuchAlgorithmException", e);
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            throw new Exception("NoSuchPaddingException", e);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new Exception("InvalidKeyException", e);

        }

        try {

            byte[] buf = cipher.doFinal(Base64Utils.decode(secretData.toCharArray()));

            return new String(buf);

        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            throw new Exception("IllegalBlockSizeException", e);
        } catch (BadPaddingException e) {
            e.printStackTrace();
            throw new Exception("BadPaddingException", e);
        }
    }

    /**
     * 得到祕密密鑰
     * 
     * @param secretKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws InvalidKeyException
     */
    private static SecretKey generateKey(String secretKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
        DESKeySpec keySpec = new DESKeySpec(secretKey.getBytes());
        keyFactory.generateSecret(keySpec);
        return keyFactory.generateSecret(keySpec);
    }

    static private class Base64Utils {

        static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
                .toCharArray();
        static private byte[] codes = new byte[256];

        static {
            for (int i = 0; i < 256; i++)
                codes[i] = -1;
            for (int i = 'A'; i <= 'Z'; i++)
                codes[i] = (byte) (i - 'A');
            for (int i = 'a'; i <= 'z'; i++)
                codes[i] = (byte) (26 + i - 'a');
            for (int i = '0'; i <= '9'; i++)
                codes[i] = (byte) (52 + i - '0');
            codes['+'] = 62;
            codes['/'] = 63;
        }

        /**
         * 將原始數據編碼爲base64編碼
         */
        static private String encode(byte[] data) {
            char[] out = new char[((data.length + 2) / 3) * 4];
            for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
                boolean quad = false;
                boolean trip = false;
                int val = (0xFF & (int) data[i]);
                val <<= 8;
                if ((i + 1) < data.length) {
                    val |= (0xFF & (int) data[i + 1]);
                    trip = true;
                }
                val <<= 8;
                if ((i + 2) < data.length) {
                    val |= (0xFF & (int) data[i + 2]);
                    quad = true;
                }
                out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
                val >>= 6;
                out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
                val >>= 6;
                out[index + 1] = alphabet[val & 0x3F];
                val >>= 6;
                out[index + 0] = alphabet[val & 0x3F];
            }

            return new String(out);
        }

        /**
         * 將base64編碼的數據解碼成原始數據
         */
        static private byte[] decode(char[] data) {
            int len = ((data.length + 3) / 4) * 3;
            if (data.length > 0 && data[data.length - 1] == '=')
                --len;
            if (data.length > 1 && data[data.length - 2] == '=')
                --len;
            byte[] out = new byte[len];
            int shift = 0;
            int accum = 0;
            int index = 0;
            for (int ix = 0; ix < data.length; ix++) {
                int value = codes[data[ix] & 0xFF];
                if (value >= 0) {
                    accum <<= 6;
                    shift += 6;
                    accum |= value;
                    if (shift >= 8) {
                        shift -= 8;
                        out[index++] = (byte) ((accum >> shift) & 0xff);
                    }
                }
            }
            if (index != out.length)
                throw new Error("miscalculated data length!");
            return out;
        }
    }
}

    3.2 當用戶訪問登陸頁,向瀏覽器寫入一個40位的密匙

        代碼就不貼了,就是用random生成,而後用model寫回去數組

     3.3 使用JQ同步加密數據

        當用戶在文本框輸入帳號密碼的時候,須要向隱藏域中實時的寫入當前用戶輸入數據的加密值。代碼以下:       瀏覽器

function synchronize(){ 
	var NewUser = $("#um").val();
	var NewPass = $("#pw").val();
	var ranDom = $("#random").val();
    //NewPass是用戶輸入值,ranDom是加密密匙
    document.getElementById('pw1').value =encryptByDES(NewPass, ranDom); 
    document.getElementById('um1').value =encryptByDES(NewUser, ranDom); 
 } 
  //執行同步 
  setInterval(synchronize,300);//同步的時間間隔,每0.3秒同步一次

    而後提交表單的時候,把隱藏域中加密好的用戶名密碼及加密密匙傳回後臺進行解密,再去查數據庫判斷就OK了!dom

    下面是加密數據的效果圖:能夠看到全部數據已經加密工具

      而後我再補一張服務端解密的Debug圖:首先能夠看到傳來的用戶名密碼都是加密的。大數據

    接下來是解密成原始數據,數據已經成功解密!!

相關文章
相關標籤/搜索