DES/3DES加密,解密


作者:xcbeyond
疯狂源自梦想,技术成就辉煌!微信公众号:《程序猿技术大咖》号主,专注后端开发多年,拥有丰富的研发经验,乐于技术输出、分享,现阶段从事微服务架构项目的研发工作,涉及架构设计、技术选型、业务研发等工作。对于Java、微服务、数据库、Docker有深入了解,并有大量的调优经验。 






   




〇、前言

        最近在项目中,涉及到与第三方厂家系统进行对接时,在参数传递过程中考虑到了数据的安全性,故双方采用3DES进行对传递参数的加解密,因此,进一步了解了下3DES的加解密算法,再次进行梳理。
一、DES算法

     DES,Data Encryption Standard,即:数据加密标准,是一种使用密钥加密的块算法。

      DES算法在POS、ATM、磁卡及IC卡、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。

      1、DES算法的入口参数有三个: Key、Data、Mode。

      其中Key为8个字节共64位,是DES算法的工作密钥;

        Data也为8个字节64位,是要被加密或被解密的数据;

        Mode为DES的工作方式,有两种:加密或解密。
      2、DES算法过程:

  如果mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;

  如果mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。

  在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。

  通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。

        (PS:不过在当今为了数据的更安全,一般采用加密平台进行数据的硬加密,实现数据明文不落地,尤其是在金融行业尤为运用广泛。)

       3、DES算法步骤

       DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位(实际用到了56位,第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),其算法主要分为两步:
   ①初始置换
       其功能是把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,其置换规则为将输入的第58位换到第一位,第50位换到第2位……依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分,L0是输出的左32位,R0是右32位,例:设置换前的输入值为D1D2D3……D64,则经过初始置换后的结果为: L0=D58D50……D8;R0=D57D49……D7。
    其置换规则见下表:
    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
   ②逆置换
     经过16次迭代运算后,得到L16、R16,将此作为输入,进行逆置换,逆置换正好是初始置换的逆运算,由此即得到密文输出。
     此算法是对称加密算法体系中的代表,在计算机网络系统中广泛使用。

4、DES算法实现
    见 "三、算法实现"

二、3DES算法

       3DES(又称Triple DES),是进行了三重数据加密,即:每个数据块进行了三次DES加密算法,使用3条64位的密钥对数据进行三次加密,故比DES加密更为安全,更难破解。

   1、加密算法,其具体实现如下:

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

      注:K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位。

     2、3DES算法实现

      (见 "三、算法实现")
三、算法实现

1、Java实现


    <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";
            //待加密数据
            String data = "1000000";
            
            System.out.println("加密前的数据为:" + data);
            System.out.println();
            
            //DES加解密
            String encoded = encryptDES(getDesKey(key), data.getBytes());
            System.out.println("DES加密后的数据为:" + encoded);
            String decoded = decryptDES(getDesKey(key), hexStringToBytes(encoded));
            System.out.println("DES解密后的数据为:" + new String(decoded));
            System.out.println();
            
            encoded = encrypt3DES(get3DesKey(key), data.getBytes());
            System.out.println("3DES加密后的数据为:" + encoded);
            decoded = decrypt3DES(get3DesKey(key), hexStringToBytes(encoded));
            System.out.println("3DES解密后的数据为:" + new String(decoded));
            
            
            
          }
     
           /**
         * 生成24字节的3DES密钥。
         * (不够24字节,则补0;超过24字节,则取前24字节。)
         * @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字节的DES密钥。
         * (不够8字节,则补0;超过8字节,则取前8字节。)
         * @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    :被加密的数据
         * @return
         *         加密后的数据
         */
        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进制数返回
            return getHexString(retValue);
        }
     
        /**
         * 3DES解密
         * @param
         *         key    :解密密钥
         *         value    :被解密的数据
         * @return
         *         解密后的明文数据
         */
        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    :被加密的数据
         * @return
         *         加密后的数据
         */
        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进制数返回
            return getHexString(retValue);
        }
     
        /**
         * DES解密
         * @param
         *         key    :解密密钥
         *         value    :被加密的数据
         * @return
         *         加解密后的明文数据
         */
        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进制数
         * @param data
         * @return   
         *         16进制数
         */
        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数组
         * @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中需要待加密或解密数据后追加字符串结束符“\0”,否则造成相互加解密存在数据差异。


2、Delphi实现

    <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=( //位选择函数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=( //置换函数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进制字符串
      参数: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解密成字符串
      参数: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))))
      参数: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))))
      参数: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>