DES/3DES加密,解密


作者:xcbeyond
瘋狂源自夢想,技術成就輝煌!微信公眾號:《程序猿技術大咖》號主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗,樂于技術輸出、分享,現(xiàn)階段從事微服務架構項目的研發(fā)工作,涉及架構設計、技術選型、業(yè)務研發(fā)等工作。對于Java、微服務、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗。 






   




〇、前言

        最近在項目中,涉及到與第三方廠家系統(tǒng)進行對接時,在參數(shù)傳遞過程中考慮到了數(shù)據(jù)的安全性,故雙方采用3DES進行對傳遞參數(shù)的加解密,因此,進一步了解了下3DES的加解密算法,再次進行梳理。
一、DES算法

     DES,Data Encryption Standard,即:數(shù)據(jù)加密標準,是一種使用密鑰加密的塊算法。

      DES算法在POS、ATM、磁卡及IC卡、加油站、高速公路收費站等領域被廣泛應用,以此來實現(xiàn)關鍵數(shù)據(jù)的保密,如信用卡持卡人的PIN的加密傳輸,IC卡與POS間的雙向認證、金融交易數(shù)據(jù)包的MAC校驗等,均用到DES算法。

      1、DES算法的入口參數(shù)有三個: Key、Data、Mode。

      其中Key為8個字節(jié)共64位,是DES算法的工作密鑰;

        Data也為8個字節(jié)64位,是要被加密或被解密的數(shù)據(jù);

        Mode為DES的工作方式,有兩種:加密或解密。
      2、DES算法過程:

  如果mode為加密,則用Key 去把數(shù)據(jù)Data進行加密, 生成Data的密碼形式(64位)作為DES的輸出結果;

  如果mode為解密,則用Key去把密碼形式的數(shù)據(jù)Data解密,還原為Data的明碼形式(64位)作為DES的輸出結果。

  在通信網(wǎng)絡的兩端,雙方約定一致的Key,在通信的源點用Key對核心數(shù)據(jù)進行DES加密,然后以密碼形式在公共通信網(wǎng)(如電話網(wǎng))中傳輸?shù)酵ㄐ啪W(wǎng)絡的終點,數(shù)據(jù)到達目的地后,用同樣的Key對密碼數(shù)據(jù)進行解密,便再現(xiàn)了明碼形式的核心數(shù)據(jù)。這樣,便保證了核心數(shù)據(jù)(如PIN、MAC等)在公共通信網(wǎng)中傳輸?shù)陌踩院涂煽啃浴?br>
  通過定期在通信網(wǎng)絡的源端和目的端同時改用新的Key,便能更進一步提高數(shù)據(jù)的保密性,這正是現(xiàn)在金融交易網(wǎng)絡的流行做法。

        (PS:不過在當今為了數(shù)據(jù)的更安全,一般采用加密平臺進行數(shù)據(jù)的硬加密,實現(xiàn)數(shù)據(jù)明文不落地,尤其是在金融行業(yè)尤為運用廣泛。)

       3、DES算法步驟

       DES算法把64位的明文輸入塊變?yōu)?4位的密文輸出塊,它所使用的密鑰也是64位(實際用到了56位,第8、16、24、32、40、48、56、64位是校驗位,使得每個密鑰都有奇數(shù)個1),其算法主要分為兩步:
   ①初始置換
       其功能是把輸入的64位數(shù)據(jù)塊按位重新組合,并把輸出分為L0、R0兩部分,每部分各長32位,其置換規(guī)則為將輸入的第58位換到第一位,第50位換到第2位……依此類推,最后一位是原來的第7位。L0、R0則是換位輸出后的兩部分,L0是輸出的左32位,R0是右32位,例:設置換前的輸入值為D1D2D3……D64,則經(jīng)過初始置換后的結果為: L0=D58D50……D8;R0=D57D49……D7。
    其置換規(guī)則見下表:
    58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,
    62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,
    57,49,41,33,25,17,9, 1,59,51,43,35,27,19,11,3,
    61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,  7
   ②逆置換
     經(jīng)過16次迭代運算后,得到L16、R16,將此作為輸入,進行逆置換,逆置換正好是初始置換的逆運算,由此即得到密文輸出。
     此算法是對稱加密算法體系中的代表,在計算機網(wǎng)絡系統(tǒng)中廣泛使用。

4、DES算法實現(xiàn)
    見 "三、算法實現(xiàn)"

二、3DES算法

       3DES(又稱Triple DES),是進行了三重數(shù)據(jù)加密,即:每個數(shù)據(jù)塊進行了三次DES加密算法,使用3條64位的密鑰對數(shù)據(jù)進行三次加密,故比DES加密更為安全,更難破解。

   1、加密算法,其具體實現(xiàn)如下:

      設Ek()和Dk()代表DES算法的加密和解密過程,K代表DES算法使用的密鑰,M代表明文,C代表密文:
        3DES加密過程為:C=Ek3(Dk2(Ek1(M)))
        3DES解密過程為:M=Dk1(EK2(Dk3(C)))

      注:K1、K2、K3決定了算法的安全性,若三個密鑰互不相同,本質(zhì)上就相當于用一個長為168位的密鑰進行加密。多年來,它在對付強力攻擊時是比較安全的。若數(shù)據(jù)對安全性要求不那么高,K1可以等于K3。在這種情況下,密鑰的有效長度為112位。

     2、3DES算法實現(xiàn)

      (見 "三、算法實現(xiàn)")
三、算法實現(xiàn)

1、Java實現(xiàn)


    <span style="font-size:12px;">package com.xcbeyond.security;
     
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
     
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    /**
     * 加解密工具類
     * @author xcbeyond
     * 2016-8-6下午11:16:46
     */
    public class ScrtUtil {
        private static final Log log = LogFactory.getLog(ScrtUtil.class);
        private static final String DES3 = "DESede";
        private static final String DES = "DES";
     
            /**
          * 測試方法
          * @param args
          */
         public static void main(String[] args) {
            //密鑰
            String key = "0123456789asdfghjklzxcvbnmqwertyuiop";
            //待加密數(shù)據(jù)
            String data = "1000000";
            
            System.out.println("加密前的數(shù)據(jù)為:" + data);
            System.out.println();
            
            //DES加解密
            String encoded = encryptDES(getDesKey(key), data.getBytes());
            System.out.println("DES加密后的數(shù)據(jù)為:" + encoded);
            String decoded = decryptDES(getDesKey(key), hexStringToBytes(encoded));
            System.out.println("DES解密后的數(shù)據(jù)為:" + new String(decoded));
            System.out.println();
            
            encoded = encrypt3DES(get3DesKey(key), data.getBytes());
            System.out.println("3DES加密后的數(shù)據(jù)為:" + encoded);
            decoded = decrypt3DES(get3DesKey(key), hexStringToBytes(encoded));
            System.out.println("3DES解密后的數(shù)據(jù)為:" + new String(decoded));
            
            
            
          }
     
           /**
         * 生成24字節(jié)的3DES密鑰。
         * (不夠24字節(jié),則補0;超過24字節(jié),則取前24字節(jié)。)
         * @param key 密鑰字符串
         * @return
         */
        public static byte[] get3DesKey(String key) {
            byte[] keyBytes = new byte[24];
            if(key.getBytes().length > 24) {
                for(int i = 0;i<24;i++) {
                    keyBytes[i] = key.getBytes()[i];
                }
            } else {
                for(int i = 0;i<24;i++) {
                    if(i < key.getBytes().length) {
                        keyBytes[i] = key.getBytes()[i];
                    } else {
                        keyBytes[i] = 0x00;
                    }
                }
            }
            return keyBytes;
        }
     
        /**
         * 生成8字節(jié)的DES密鑰。
         * (不夠8字節(jié),則補0;超過8字節(jié),則取前8字節(jié)。)
         * @param key 密鑰字符串
         * @return
         */
        public static byte[] getDesKey(String key) {
            byte[] keyBytes = new byte[8];
            if(key.getBytes().length > 8) {
                for(int i = 0;i<8;i++) {
                    keyBytes[i] = key.getBytes()[i];
                }
            } else {
                for(int i = 0;i<8;i++) {
                    if(i < key.getBytes().length) {
                        keyBytes[i] = key.getBytes()[i];
                    } else {
                        keyBytes[i] = 0x00;
                    }
                }
            }
            return keyBytes;
        }
     
        /**
         * 3DES加密
         * @param
         *         key    :加密密鑰
         *         value    :被加密的數(shù)據(jù)
         * @return
         *         加密后的數(shù)據(jù)
         */
        public static String encrypt3DES(byte[] key, byte[] value) {
            byte[] retValue = null;
            try {
                SecretKey deskey = new SecretKeySpec(key, DES3);
                Cipher c1 = Cipher.getInstance(DES3);
                c1.init(1, deskey);
                retValue = c1.doFinal(value);
            } catch (Exception ex) {
                if(log.isErrorEnabled()) {
                    log.error("3DES加密錯誤" + ex);
                }
            }
           
            //轉換為16進制數(shù)返回
            return getHexString(retValue);
        }
     
        /**
         * 3DES解密
         * @param
         *         key    :解密密鑰
         *         value    :被解密的數(shù)據(jù)
         * @return
         *         解密后的明文數(shù)據(jù)
         */
        public static String decrypt3DES(byte[] key, byte[] value) {
            byte[] retValue = null;
            try {
                SecretKey deskey = new SecretKeySpec(key, DES3);
                Cipher c1 = Cipher.getInstance(DES3);
                c1.init(2, deskey);
                retValue = c1.doFinal(value);
            } catch (Exception ex) {
                if(log.isErrorEnabled()) {
                    log.error("3DES解密錯誤" + ex);
                }
            }
            return new String(retValue);
        }
     
        /**
         * DES加密
         * @param
         *         key    :加密密鑰
         *         value    :被加密的數(shù)據(jù)
         * @return
         *         加密后的數(shù)據(jù)
         */
        public static String encryptDES(byte[] key, byte[] value) {
            byte[] retValue = null;
            try {
                SecretKey deskey = new SecretKeySpec(key, DES);
                Cipher c1 = Cipher.getInstance(DES);
                c1.init(1, deskey);
                retValue = c1.doFinal(value);
            } catch (Exception ex) {
                if(log.isErrorEnabled()) {
                    log.error("DES加密錯誤" + ex);
                }
            }
           
            //轉換為16進制數(shù)返回
            return getHexString(retValue);
        }
     
        /**
         * DES解密
         * @param
         *         key    :解密密鑰
         *         value    :被加密的數(shù)據(jù)
         * @return
         *         加解密后的明文數(shù)據(jù)
         */
        public static String decryptDES(byte[] key, byte[] value) {
            byte[] retValue = null;
            try {
                SecretKey deskey = new SecretKeySpec(key, DES);
                Cipher c1 = Cipher.getInstance(DES);
                c1.init(2, deskey);
                retValue = c1.doFinal(value);
            } catch (Exception ex) {
                if(log.isErrorEnabled()) {
                    log.error("DES解密錯誤" + ex);
                }
            }
            return new String(retValue);
        }
       
        /*
         * 轉換為16進制數(shù)
         * @param data
         * @return   
         *         16進制數(shù)
         */
        public static String getHexString(byte[] data) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; ++i) {
                String ch = Integer.toHexString(data[i] & 0xFF).toUpperCase();
                if (ch.length() == 2)
                    sb.append(ch);
                else
                    sb.append("0").append(ch);
            }
            return sb.toString();
        }
       
         /**
         * 將16進制的字符串轉換為byte數(shù)組
         * @param hexString
         * @return
         */
        public static byte[] hexStringToBytes(String hexString) {  
            if (hexString == null || hexString.equals("")) {  
                return null;  
            }
            hexString = hexString.toUpperCase();  
            int length = hexString.length() / 2;  
            char[] hexChars = hexString.toCharArray();  
            byte[] d = new byte[length];  
            for (int i = 0; i < length; i++) {  
                int pos = i * 2;  
                d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));  
            }  
            return d;  
        }
        
        public static byte charToByte(char c) {  
            return (byte) "0123456789ABCDEF".indexOf(c);  
        }
    }</span>

溫馨注意:

        Java與其它語言進行相互加密、解密時,應在java中需要待加密或解密數(shù)據(jù)后追加字符串結束符“\0”,否則造成相互加解密存在數(shù)據(jù)差異。


2、Delphi實現(xiàn)

    <span style="font-size:12px;">//---------------------------------------------------------------------------
    //包含DES加/解密和3DES加/解密
    //---------------------------------------------------------------------------
    unit DesCipher;
    //---------------------------------------------------------------------------
    interface
    //---------------------------------------------------------------------------
    uses
        SysUtils, StrUtils;
    //---------------------------------------------------------------------------
    type
        TKeyByte=array[0..5] of Byte;
        TDesMode=(dmEncry, dmDecry);
        function DesEncryStrHex(Str, Key: string): string;
        function DesDecryStrHex(StrHex, Key: string): string;
        function TripleDesEncryStrHex(Str, Key: string): string;
        function TripleDesDecryStrHex(StrHex, Key: string): string;
    //---------------------------------------------------------------------------
    const
        BitIP: array[0..63] of Byte=( //初始值置IP
            57, 49, 41, 33, 25, 17,  9, 1,
            59, 51, 43, 35, 27, 19, 11, 3,
            61, 53, 45, 37, 29, 21, 13, 5,
            63, 55, 47, 39, 31, 23, 15, 7,
            56, 48, 40, 32, 24, 16,  8, 0,
            58, 50, 42, 34, 26, 18, 10, 2,
            60, 52, 44, 36, 28, 20, 12, 4,
            62, 54, 46, 38, 30, 22, 14, 6 );
        
        BitCP: array[0..63] of Byte=( //逆初始置IP-1
            39, 7, 47, 15, 55, 23, 63, 31,
            38, 6, 46, 14, 54, 22, 62, 30,
            37, 5, 45, 13, 53, 21, 61, 29,
            36, 4, 44, 12, 52, 20, 60, 28,
            35, 3, 43, 11, 51, 19, 59, 27,
            34, 2, 42, 10, 50, 18, 58, 26,
            33, 1, 41,  9, 49, 17, 57, 25,
            32, 0, 40,  8, 48, 16, 56, 24 );
        
       




BitExp: array[0..47] of Integer=( //位選擇函數(shù)E
            31,  0,  1,  2,  3,  4,  3,  4,  5,  6,  7,  8,  7,  8,  9, 10,
            11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20,
            21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31,  0 );
        
        BitPM: array[0..31] of Byte=( //置換函數(shù)P
            15, 6, 19, 20, 28, 11, 27, 16,  0, 14, 22, 25,  4, 17, 30,  9,
             1, 7, 23, 13, 31, 26,  2,  8, 18, 12, 29,  5, 21, 10,  3, 24 );
        
        sBox: array[0..7] of array[0..63] of Byte=( //S盒
            (14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
              0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
              4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
             15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13 ),    
            (15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
              3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
              0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
             13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9 ),    
            (10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
             13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
             13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
              1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12 ),    
            ( 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
             13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
             10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
              3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14 ),    
            ( 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
             14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
              4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
             11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3 ),
            (12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
             10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
              9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
              4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13 ),
            ( 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
             13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
              1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
              6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12 ),
            (13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
              1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
              7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
              2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11 ));
        
        BitPMC1: array[0..55] of Byte=( //選擇置換PC-1
            56, 48, 40, 32, 24, 16,  8,
             0, 57, 49, 41, 33, 25, 17,
             9,  1, 58, 50, 42, 34, 26,
            18, 10,  2, 59, 51, 43, 35,
            62, 54, 46, 38, 30, 22, 14,
             6, 61, 53, 45, 37, 29, 21,
            13,  5, 60, 52, 44, 36, 28,
            20, 12,  4, 27, 19, 11,  3 );
        
        BitPMC2: array[0..47] of Byte=( //選擇置換PC-2
            13, 16, 10, 23,  0,  4,
             2, 27, 14,  5, 20,  9,
            22, 18, 11,  3, 25,  7,
            15,  6, 26, 19, 12,  1,
            40, 51, 30, 36, 46, 54,
            29, 39, 50, 44, 32, 47,
            43, 48, 38, 55, 33, 52,
            45, 41, 49, 35, 28, 31 );
    //---------------------------------------------------------------------------
    var
        subKey: array[0..15] of TKeyByte;
    //---------------------------------------------------------------------------
    implementation
    //---------------------------------------------------------------------------
    procedure initPermutation(var inData: array of Byte);
    var
        newData: array[0..7] of Byte;  i: Integer;
    begin
        FillChar(newData,8,0);
        for i:=0 to 63 do begin
            if (inData[BitIP[i] shr 3] and (1 shl (7-(BitIP[i] and $07))))<>0 then begin
                newData[i shr 3] := newData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
        for i:=0 to 7 do inData[i] := newData[i];
    end;
    //---------------------------------------------------------------------------
    procedure conversePermutation(var inData: array of Byte);
    var
        newData: array[0..7] of Byte;  i: Integer;
    begin
        FillChar(newData,8,0);
        for i:=0 to 63 do begin
            if (inData[BitCP[i] shr 3] and (1 shl (7-(BitCP[i] and $07))))<>0 then begin
                newData[i shr 3] := newData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
        for i:=0 to 7 do inData[i] := newData[i];
    end;
    //---------------------------------------------------------------------------
    procedure expand(inData: array of Byte; var outData: array of Byte);
    var
        i: Integer;
    begin
        FillChar(outData,6,0);
        for i:=0 to 47 do begin
            if (inData[BitExp[i] shr 3] and (1 shl (7-(BitExp[i] and $07))))<>0 then begin
                outData[i shr 3] := outData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
    end;
    //---------------------------------------------------------------------------
    procedure permutation(var inData: array of Byte);
    var
        newData: array[0..3] of Byte;  i: Integer;
    begin
        FillChar(newData,4,0);
        for i:=0 to 31 do begin
            if (inData[BitPM[i] shr 3] and (1 shl (7-(BitPM[i] and $07))))<>0 then begin
                newData[i shr 3] := newData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
        for i:=0 to 3 do inData[i] := newData[i];
    end;
    //---------------------------------------------------------------------------
    function si(s, inByte: Byte): Byte;
    var
        c: Byte;
    begin
        c := (inByte and $20) or ((inByte and $1e) shr 1) or ((inByte and $01) shl 4);
        Result := (sBox[s][c] and $0f);
    end;
    //---------------------------------------------------------------------------
    procedure permutationChoose1(inData: array of Byte; var outData: array of Byte);
    var
        i: Integer;
    begin
        FillChar(outData,7,0);
        for i:=0 to 55 do begin
            if (inData[BitPMC1[i] shr 3] and (1 shl (7-(BitPMC1[i] and $07))))<>0 then begin
                outData[i shr 3] := outData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
    end;
    //---------------------------------------------------------------------------
    procedure permutationChoose2(inData: array of Byte; var outData: array of Byte);
    var
        i: Integer;
    begin
        FillChar(outData, 6, 0);
        for i:=0 to 47 do begin
            if (inData[BitPMC2[i] shr 3] and (1 shl (7-(BitPMC2[i] and $07))))<>0 then begin
                outData[i shr 3] := outData[i shr 3] or (1 shl (7-(i and $07)));
            end;
        end;
    end;
    //---------------------------------------------------------------------------
    procedure cycleMove(var inData: array of Byte; bitMove: Byte);
    var
        i: Integer;
    begin
        for i:=0 to bitMove-1 do begin
            inData[0] := (inData[0] shl 1) or (inData[1] shr 7);
            inData[1] := (inData[1] shl 1) or (inData[2] shr 7);
            inData[2] := (inData[2] shl 1) or (inData[3] shr 7);
            inData[3] := (inData[3] shl 1) or ((inData[0] and $10) shr 4);
            inData[0] := (inData[0] and $0f);
        end;
    end;
    //---------------------------------------------------------------------------
    procedure makeKey(inKey: array of Byte; var outKey: array of TKeyByte);
    const
        bitDisplace: array[0..15] of Byte=(1,1,2,2, 2,2,2,2, 1,2,2,2, 2,2,2,1);
    var
        outData56: array[0..6] of Byte;  key56o: array[0..6] of Byte;
        key28l: array[0..3] of Byte;  key28r: array[0..3] of Byte;  i: Integer;
    begin
        permutationChoose1(inKey,outData56);
        key28l[0] := outData56[0] shr 4;
        key28l[1] := (outData56[0] shl 4) or (outData56[1] shr 4);
        key28l[2] := (outData56[1] shl 4) or (outData56[2] shr 4);
        key28l[3] := (outData56[2] shl 4) or (outData56[3] shr 4);
        key28r[0] := outData56[3] and $0f;
        key28r[1] := outData56[4];
        key28r[2] := outData56[5];
        key28r[3] := outData56[6];
        for i:=0 to 15 do begin
            cycleMove(key28l,bitDisplace[i]);
            cycleMove(key28r,bitDisplace[i]);
            key56o[0] := (key28l[0] shl 4) or (key28l[1] shr 4);
            key56o[1] := (key28l[1] shl 4) or (key28l[2] shr 4);
            key56o[2] := (key28l[2] shl 4) or (key28l[3] shr 4);
            key56o[3] := (key28l[3] shl 4) or (key28r[0]);
            key56o[4] := key28r[1];
            key56o[5] := key28r[2];
            key56o[6] := key28r[3];
            permutationChoose2(key56o,outKey[i]);
        end;
    end;
    //---------------------------------------------------------------------------
    procedure encry(inData, subKey: array of Byte; var outData: array of Byte);
    var
        outBuf: array[0..5] of Byte;  buf: array[0..7] of Byte;  i: Integer;
    begin
        expand(inData,outBuf);
        for i:=0 to 5 do outBuf[i] := outBuf[i] xor subKey[i];
        buf[0] := outBuf[0] shr 2;
        buf[1] := ((outBuf[0] and $03) shl 4) or (outBuf[1] shr 4);
        buf[2] := ((outBuf[1] and $0f) shl 2) or (outBuf[2] shr 6);
        buf[3] := outBuf[2] and $3f;
        buf[4] := outBuf[3] shr 2;
        buf[5] := ((outBuf[3] and $03) shl 4) or (outBuf[4] shr 4);
        buf[6] := ((outBuf[4] and $0f) shl 2) or (outBuf[5] shr 6);
        buf[7] := outBuf[5] and $3f;                                
        for i:=0 to 7 do buf[i] := si(i, buf[i]);
        for i:=0 to 3 do outBuf[i] := (buf[i*2] shl 4) or buf[i*2+1];
        permutation(outBuf);
        for i:=0 to 3 do outData[i] := outBuf[i];
    end;
    //---------------------------------------------------------------------------
    procedure desData(desMode: TDesMode; inData: array of Byte; var outData: array of Byte);
    var
        i, j: Integer;  temp, buf: array[0..3] of Byte;
    begin
        for i:=0 to 7 do outData[i] := inData[i];
        initPermutation(outData);
        if desMode=dmEncry then begin
            for i:=0 to 15 do begin
                for j:=0 to 3 do temp[j] := outData[j];
                for j:=0 to 3 do outData[j] := outData[j+4];
                encry(outData,subKey[i],buf);
                for j:=0 to 3 do outData[j+4] := temp[j] xor buf[j];
            end;
            for j:=0 to 3 do temp[j] := outData[j+4];
            for j:=0 to 3 do outData[j+4] := outData[j];
            for j:=0 to 3 do outData[j] := temp[j];
        end
        else if desMode=dmDecry then begin
            for i:=15 downto 0 do begin
                for j:=0 to 3 do temp[j] := outData[j];
                for j:=0 to 3 do outData[j] := outData[j+4];
                encry(outData, subKey[i], buf);
                for j:=0 to 3 do outData[j+4] := temp[j] xor buf[j];
            end;
            for j:=0 to 3 do temp[j] := outData[j+4];
            for j:=0 to 3 do outData[j+4] := outData[j];
            for j:=0 to 3 do outData[j] := temp[j];
        end;
        conversePermutation(outData);
    end;
    //---------------------------------------------------------------------------
    function HexToInt(Hex: string): Integer;
    var
        I, Res: Integer;  ch: Char;
    begin
        Res := 0;
        for I:=0 to Length(Hex)-1 do begin
            ch := Hex[I+1];
            if (ch>='0') and (ch<='9') then Res := Res*16+Ord(ch)-Ord('0')
            else if (ch>='A') and (ch<='F') then Res := Res*16+Ord(ch)-Ord('A')+10
            else if (ch>='a') and (ch<='f') then Res := Res*16+Ord(ch)-Ord('a')+10
            else raise Exception.Create('Error: Not a hex string.');
        end;
        Result := Res;
    end;
    //---------------------------------------------------------------------------
    function DesEncryStr(Str, Key: string): string;
    var
        StrByte, OutByte, KeyByte: array[0..7] of Byte;
        StrResult: string;  I, J: Integer;
    begin
        if (Length(Str)>0) and (Ord(Str[Length(Str)])=0) then begin
            raise Exception.Create('Error: The last char is nil char.');
        end;
        if Length(Key)<8 then begin
            while Length(Key)<8 do Key := Key+Chr(0);
        end;
        while (Length(Str) mod 8)<>0 do Str := Str+Chr(0);
        for J:=0 to 7 do KeyByte[J] := Ord(Key[J+1]);
        makeKey(keyByte,subKey);  StrResult := '';
        for I:=0 to (Length(Str) div 8)-1 do begin
            for J:=0 to 7 do StrByte[J] := Ord(Str[I*8+J+1]);
            desData(dmEncry,StrByte,OutByte);
            for J:=0 to 7 do StrResult := StrResult+Chr(OutByte[J]);
        end;
        Result := StrResult;
    end;
    //---------------------------------------------------------------------------
    function DesDecryStr(Str, Key: string): string;
    var
        StrByte, OutByte, KeyByte: array[0..7] of Byte;
        StrResult: string;  I, J: Integer;
    begin
        if Length(Key)<8 then begin
            while Length(Key)<8 do Key := Key+Chr(0);
        end;
        for J:=0 to 7 do KeyByte[J] := Ord(Key[J+1]);
        makeKey(keyByte,subKey);  StrResult := '';
        for I:=0 to (Length(Str) div 8)-1 do begin
            for J:=0 to 7 do StrByte[J] := Ord(Str[I*8+J+1]);
            desData(dmDecry,StrByte,OutByte);
            for J:=0 to 7 do StrResult := StrResult+Chr(OutByte[J]);
        end;
        while (Length(StrResult)>0) and (Ord(StrResult[Length(StrResult)])=0) do begin
            Delete(StrResult,Length(StrResult),1);
        end;
        Result := StrResult;
    end;
    //---------------------------------------------------------------------------
    { 功能:將字符串DES加密成16進制字符串
      參數(shù):Str:[in]待加密的字符串; Key:[in]密鑰
      返回值:加密后的16進制字符串 }
    function DesEncryStrHex(Str, Key: string): string;
    var
        StrResult, TempResult, Temp: string;  I: Integer;
    begin
        TempResult := DesEncryStr(Str,Key);  StrResult := '';
        for I:=0 to Length(TempResult)-1 do begin
            Temp := Format('%x',[Ord(TempResult[I+1])]);
            if Length(Temp)=1 then Temp := '0'+Temp;
            StrResult := StrResult+Temp;
        end;
        Result := StrResult;
    end;
    //---------------------------------------------------------------------------
    { 功能:將16進制字符串DES解密成字符串
      參數(shù):StrHex:[in]待解密的16進制字符串; Key:[in]密鑰
      返回值:解密后的字符串 }
    function DesDecryStrHex(StrHex, Key: string): string;
    var
        Str, Temp: string;  I: Integer;
    begin
        Str := '';
        for I:=0 to (Length(StrHex) div 2)-1 do begin
            Temp := Copy(StrHex,I*2+1,2);
            Str := Str+Chr(HexToInt(Temp));
        end;
        Result := DesDecryStr(Str,Key);
    end;
    //---------------------------------------------------------------------------
    { 功能:將字符串3DES加密成16進制字符串(Ek3(Dk2(Ek1(Str))))
      參數(shù):Str:[in]待加密的字符串; Key:[in]密鑰
      返回值:加密后的16進制字符串 }
    function TripleDesEncryStrHex(Str, Key: string): string;
    var
        TempResult, Key1, Key2, Key3: string;
    begin
        Key1 := MidStr(Key,1,8);  Key2 := MidStr(Key,9,8);
        Key3 := MidStr(Key,17,8);
        TempResult := DesEncryStrHex(Str,Key1);
        TempResult := DesDecryStrHex(TempResult,Key2);
        Result := DesEncryStrHex(TempResult,Key3);
    end;
    //---------------------------------------------------------------------------
    { 功能:將16進制字符串3DES解密成字符串(Dk1(Ek2(Dk3(StrHex))))
      參數(shù):StrHex:[in]待解密的16進制字符串; Key:[in]密鑰
      返回值:解密后的字符串 }
    function TripleDesDecryStrHex(StrHex, Key: string): string;
    var
        Temp, Key1, Key2, Key3: string;
    begin
        Key1 := MidStr(Key,1,8);  Key2 := MidStr(Key,9,8);
        Key3 := MidStr(Key,17,8);
        Temp := DesDecryStrHex(StrHex,Key3);
        Temp := DesEncryStrHex(Temp,Key2);
        Result := DesDecryStrHex(Temp,Key1);
    end;
    //---------------------------------------------------------------------------
    end.
    //---------------------------------------------------------------------------</span>