欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【加密解密】数据加密标准DES加密(Javascript实现)

程序员文章站 2022-03-09 22:36:33
...

■数据加密标准DES加密

DES算法为密码*中的对称密码*,又被成为美国数据加密标准,是1972年美国IBM公司研制的对称密码*加密算法。DES是Data Encryption Standard(数据加密标准)的缩写。它是由IBM公司研制的一种对称密码算法,美国国家标准局于1977年公布把它作为非机要部门使用的数据加密标准。

明文按64位进行分组, **长64位,**事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位, 使得每个**都有奇数个1)分组后的明文组和56位的**按位替代或交换的方法形成密文组的加密方法。

  DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。它的**长度是56位(因为每个第8 位都用作奇偶校验),**可以是任意的56位的数,而且可以任意时候改变。其中有极少数被认为是易**的弱**,但是很容易避开它们不用。所以保密性依赖于**。

 

DES加密的算法框架如下:

【加密解密】数据加密标准DES加密(Javascript实现)

  首先要生成一套加***,从用户处取得一个64位长的密码口令,然后通过等分、移位、选取和迭代形成一套16个加***,分别供每一轮运算中使用。

 

  DES对64位(bit)的明文分组M进行操作,M经过一个初始置换IP,置换成m0。将m0明文分成左半部分和右半部分m0 = (L0,R0),各32位长。然后进行16轮完全相同的运算(迭代),这些运算被称为函数f,在每一轮运算过程中数据与相应的**(子**)结合。

  在每一轮中,**位移位,然后再①从**的56位中选出48位(子**)。通过一个②扩展置换将数据的右半部分(R)扩展成48位,并通过③一个异或操作替代成新的48位数据,再将其压缩④置换成32位。这四步运算构成了函数f。然后,通过⑤另一个异或运算,函数f的输出与左半部分(L)结合,其结果成为新的右半部分(R),原来的右半部分(R)成为新的左半部分(L)。将该操作重复16次。

  经过16轮迭代后,左,右半部分合在一起经过一个逆初始置换(数据整理),这样就完成了加密过程。

【加密解密】数据加密标准DES加密(Javascript实现)

 

子**生成分:

第一步,先把**中的奇偶校验为去掉,然后根据选择置换PC-1讲剩下的**分成两块C0和D0;

第二步,将C0和D0进行循环左移变换,变换后生成C1和D1,然后C1和D1合并,通过选择置换PC-2生成子**K1;

第三步,C1和D1再次经过循环左移变换,生成C2和D2,C2和D2合并,通过选择置换PC-2生成子**K2;

第四步,以此类推,需要注意其中循环左移的位数,一共是循环左移十六次,其中LS1(第一次),LS2(第二次),LS9,LS16是循环左移一位,其他的都是左移两位。

【加密解密】数据加密标准DES加密(Javascript实现)

DES解密过程:

  在了解了加密过程中所有的代替、置换、异或和循环迭代之后,很多人也许会认为,解密算法应该是加密的逆运算,与加密算法完全不同。恰恰相反,经过密码学家精心设计选择的各种操作,DES获得了一个非常有用的性质:加密和解密使用相同的算法!

 

  DES加密和解密唯一的不同是**的次序相反。如果各轮加***分别是K1,K2,K3…K16,那么解***就是K16,K15,K14…K1。这也就是DES被称为对称算法的理由吧。

 

    <script language="JavaScript">
    // accumulate values to put into text area
    var accumulated_output_info;

    // add a labeled value to the text area
    function accumulate_output( str ) {
        accumulated_output_info = accumulated_output_info + str + "\n";
    }

    // add a bit string to the output, inserting spaces as designated
    function accumulate_bitstring( label, ary, spacing ) {
        var i;

        accumulated_output_info += label;

        // add bits
        for( i = 1; i < ary.length; i ++ ) {
            if ( (i%spacing) == 1 ) {
                accumulated_output_info += " ";    // time to add a space
            }
            accumulated_output_info += ary[i];    // and the bit
        }

        // insert trailing end-of-line
        accumulated_output_info += "\n";
    }

// special value stored in x[0] to indicate a problem
var ERROR_VAL = -9876;

// initial permutation (split into left/right halves )
// since DES numbers bits starting at 1, we will ignore x[0]
// 置换IP表
var IP_perm = new Array( -1,
    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 );

// final permutation (inverse initial permutation)
// 逆置换IP-1表
var FP_perm = new Array( -1,
    40, 8, 48, 16, 56, 24, 64, 32,
    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 );

// per-round expansion
// E位选择表(扩展置换表)
var E_perm = new Array( -1,
    32, 1, 2, 3, 4, 5,
    4, 5, 6, 7, 8, 9,
    8, 9, 10, 11, 12, 13,
    12, 13, 14, 15, 16, 17,
    16, 17, 18, 19, 20, 21,
    20, 21, 22, 23, 24, 25,
    24, 25, 26, 27, 28, 29,
    28, 29, 30, 31, 32, 1 );

// per-round permutation
// P换位表(单纯换位表)
var P_perm = new Array( -1,
    16, 7, 20, 21, 29, 12, 28, 17,
    1, 15, 23, 26, 5, 18, 31, 10,
    2, 8, 24, 14, 32, 27, 3, 9,
    19, 13, 30, 6, 22, 11, 4, 25 );


// note we do use element 0 in the S-Boxes
// S盒
var S1 = new Array(
    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 );
var S2 = new Array(
    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 );
var S3 = new Array(
    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 );
var S4 = new Array(
    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 );
var S5 = new Array(
    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 );
var S6 = new Array(
    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 );
var S7 = new Array(
    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 );
var S8 = new Array(
    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 );

// first, key, permutation
// PC1选位表(**生成置换表1)
var PC_1_perm = new Array( -1, 
    // C subkey bits
    57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
    10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
    // D subkey bits
    63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
    14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 );

// per-round, key, selection, permutation
// PC2选位表(**生成置换表2)
var PC_2_perm = new Array( -1, 
    14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
    23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
    41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
    44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 );

// save output in case we want to reformat it later
var DES_output = new Array( 65 );

// remove spaces from input
function remove_spaces( instr ) {
    var i;
    var outstr="";

    for( i = 0; i < instr.length; i ++ ) {
        if ( instr.charAt(i) != " " ) {
            // not a space, include it
            outstr += instr.charAt(i);
        }
    }

    return outstr;
}

// split an integer into bits
// ary   = array to store bits in
// start = starting subscript
// bitc  = number of bits to convert
// val   = number to convert
function split_int( ary, start, bitc, val ) {
    var i = start;
    var j;
    for( j =bitc - 1; j >= 0; j -- ) {
        // isolate low-order bit
        ary[i+j] = val & 1;
        // remove that bit
        val >>= 1;
    }
}

// get the message to encrypt/decrypt
function get_value( bitarray, str, isASCII ) {
    var i;
    var val;    // one hex digit

    // insert note we probably are ok
    bitarray[0] = -1;

    if ( isASCII ) {
        // check length of data
        if ( str.length != 8 ) {
            window.alert("Message and key must be 64 bits (8 ASCII characters)");
            bitarray[0] = ERROR_VAL;
            return
        }

        // have ASCII data
        for( i = 0; i < 8; i ++ ) {
            split_int( bitarray, i*8+1, 8, str.charCodeAt(i) );
        }
    } else {
        // have hex data - remove any spaces they used, then convert
        str = remove_spaces(str);

        // check length of data
        if ( str.length != 16 ) {
            window.alert("Message and key must be 64 bits (16 hex digits)");
            bitarray[0] = ERROR_VAL;
            return;
        }

        for( i = 0; i < 16; i ++ ) {
            // get the next hex digit
            val = str.charCodeAt(i);

            // do some error checking
            if ( val >= 48 && val <= 57 ) {
                // have a valid digit 0-9
                val -= 48;
            } else if ( val >= 65 && val <= 70 ) {
                // have a valid digit A-F
                val -= 55;
            } else if ( val >= 97 && val <= 102 ) {
                // have a valid digit A-F
                val -= 87;
            } else {
                // not 0-9 or A-F, complain
                window.alert( str.charAt(i)+" is not a valid hex digit" );
                bitarray[0] = ERROR_VAL;
                return;
            }

            // add this digit to the array
            split_int( bitarray, i*4+1, 4, val-48 );
        }
    }
}

// format the output in the desired form
// if -1, use existing value
// -- uses the global array DES_output
function format_DES_output( ) {
    var i;
    var bits;
    var str="";

    // what type of data do we have to work with?
    if ( document.stuff.outtype[0].checked ) {
        // convert each set of bits back to ASCII
        for( i = 1; i <= 64; i += 8 ) {
            str += String.fromCharCode(
                        DES_output[i  ]*128 + DES_output[i+1]*64  +
                        DES_output[i+2]*32  + DES_output[i+3]*16  +
                        DES_output[i+4]*8   + DES_output[i+5]*4   +
                        DES_output[i+6]*2   + DES_output[i+7] );
        }
    } else  {
        // output hexdecimal data
        for( i=1; i<=64; i+= 4 ) {
            bits = DES_output[i  ]*8   + DES_output[i+1]*4   +
                   DES_output[i+2]*2   + DES_output[i+3];

            // 0-9 or A-F?
            if ( bits <= 9 ) {
               str += String.fromCharCode( bits+48 );
            } else {
               str += String.fromCharCode( bits+87 );
            }
        }
    }

    // copy to textbox
    document.stuff.outdata.value = str;
}

// copy bits in a permutation
//   dest = where to copy the bits to
//   src  = Where to copy the bits from
//   perm = The order to copy/permute the bits
// note: since DES ingores x[0], we do also
function permute( dest, src, perm ) {
    var i;
    var fromloc;

    for( i = 1; i < perm.length; i ++ ) {
        fromloc = perm[i];
        dest[i] = src[fromloc];
    }
}

// do an array XOR
// assume all array entries are 0 or 1
function xor( a1, a2 ) {
    var i;

    for( i = 1; i < a1.length; i ++ ) {
        a1[i] = a1[i] ^ a2[i];
    }
}

// process one S-Box, return integer from S-Box
function do_S( SBox, index, inbits ) {
   // collect the 6 bits into a single integer
   var S_index = inbits[index  ]*32 + inbits[index+5]*16 +
                 inbits[index+1]*8  + inbits[index+2]*4 +
                 inbits[index+3]*2  + inbits[index+4];

   // do lookup
   return SBox[S_index];
}

// do one round of DES encryption
function des_round( L, R, KeyR ) {
    var E_result = new Array( 49 );
    var S_out    = new Array( 33 );

    // copy the existing L bits, then set new L = old R
    var temp_L = new Array( 33 );
    for( i = 0; i < 33; i ++ ) {
        // copy exising L bits
        temp_L[i] = L[i];

        // set L = R
        L[i] = R[i];
    }

    accumulate_output ("         ①从**中选出48位(子**)");

    // expand R using E permutation
    accumulate_output ("         ②扩展置换(R:32->48)");
    permute( E_result, R, E_perm );
    accumulate_bitstring( "      E   :", E_result, 6 );
    accumulate_bitstring( "      KS  :", KeyR, 6 );

    // exclusive-or with current key
    accumulate_output ("         ③一个异或操作(new 48)");
    xor( E_result, KeyR );
    accumulate_bitstring( "  E xor KS:", E_result, 6 );

    // put through the S-Boxes
    split_int( S_out,  1, 4, do_S( S1,  1, E_result ) );
    split_int( S_out,  5, 4, do_S( S2,  7, E_result ) );
    split_int( S_out,  9, 4, do_S( S3, 13, E_result ) );
    split_int( S_out, 13, 4, do_S( S4, 19, E_result ) );
    split_int( S_out, 17, 4, do_S( S5, 25, E_result ) );
    split_int( S_out, 21, 4, do_S( S6, 31, E_result ) );
    split_int( S_out, 25, 4, do_S( S7, 37, E_result ) );
    split_int( S_out, 29, 4, do_S( S8, 43, E_result ) );
    accumulate_bitstring( "      Sbox:", S_out, 4 );

    // do the P permutation
    accumulate_output ("         ④置换");
    permute( R, S_out, P_perm );
    accumulate_bitstring( "      P   :", R, 8 );

    // xor this with old L to get the new R 
    accumulate_output ("         ⑤另一个异或操作");
    xor( R, temp_L );
    accumulate_bitstring( "      L[i]:", L, 8 );
    accumulate_bitstring( "      R[i]:", R, 8 );
}

// shift the CD values left 1 bit
function shift_CD_1( CD ) {
   var i;

   // note we use [0] to hold the bit shifted around the end
   for( i=0; i<=55; i++ )
      CD[i] = CD[i+1];

   // shift D bit around end
   CD[56] = CD[28];
   // shift C bit around end
   CD[28] = CD[0];
}

// shift the CD values left 2 bits
function shift_CD_2( CD )
{
   var i;
   var C1 = CD[1];

   // note we use [0] to hold the bit shifted around the end
   for( i=0; i<=54; i++ )
      CD[i] = CD[i+2];

   // shift D bits around end
   CD[55] = CD[27];
   CD[56] = CD[28];
   // shift C bits around end
   CD[27] = C1;
   CD[28] = CD[0];
}


// do the actual DES encryption/decryption
function des_encrypt( inData, Key, do_encrypt ) {
    var tempData = new Array( 65 );    // output bits
    var CD       = new Array( 57 );    // halves of current key
    var KS       = new Array( 16 );    // per-round key schedules
    var L        = new Array( 33 );    // left half of current data
    var R        = new Array( 33 );    // right half of current data
    var result   = new Array( 65 );    // DES output
    var i;

    accumulate_output ("     生成子**:选择置换PC-1");
    // do the initial key permutation
    permute( CD, Key, PC_1_perm );
    accumulate_bitstring( "     CD[0]: ", CD, 7 );

    // create the subkeys
    for( i = 1; i <= 16; i ++ ) {
        // create a new array for each round
        KS[i] = new Array( 49 );

        // how much should we shift C and D?
        if ( i==1 || i==2 || i==9 || i == 16 ) {
            shift_CD_1( CD );
        } else {
            shift_CD_2( CD );
        }
        accumulate_output ("     生成子**:循环左移位");
        accumulate_bitstring( "     CD["+i+"]: ", CD, 7 );

        // create the actual subkey
        accumulate_output ("     生成子**:选择置换PC-2★");
        permute( KS[i], CD, PC_2_perm );
        accumulate_bitstring( "     KS["+i+"]: ", KS[i], 6 );
    }

    // handle the initial permutation
    permute( tempData, inData, IP_perm );
    accumulate_output ("-->分组M的初始置换IP完成。");

    // split data into L/R parts
    for( i = 1; i <= 32; i ++ ) {
        L[i] = tempData[i];
        R[i] = tempData[i + 32];
    }
    accumulate_bitstring( "       L[0]: ", L, 8 );
    accumulate_bitstring( "       R[0]: ", R, 8 );

    // encrypting or decrypting?
    if ( do_encrypt ) {
        // encrypting
        for( i = 1; i <= 16; i ++ ) {
            accumulate_output( "-->Round " + i );
            des_round( L, R, KS[i] );
        }
    } else {
        // decrypting
        for( i = 16; i >= 1; i -- ) {
            accumulate_output( "-->Round " + (17-i) );
            des_round( L, R, KS[i] );
        }
    }
    accumulate_output ("-->16轮函数f运算完成。");

    // create the 64-bit preoutput block = R16/L16
    for( i = 1; i <= 32; i ++ ) {
        // copy R bits into left half of block, L bits into right half
        tempData[i] = R[i];
        tempData[i+32] = L[i];
    }
    accumulate_bitstring ("     LR[16] ", tempData, 8 );

    accumulate_output ("-->逆初始置换。");
    // do final permutation and return result
    permute( result, tempData, FP_perm );
    accumulate_output ("-->加密过程完成。");

    return result;
}

// do encrytion/decryption
// do_encrypt is TRUE for encrypt, FALSE for decrypt
function do_des( do_encrypt ) {
    var inData = new Array( 65 );    // input message bits
    var Key    = new Array( 65 );

    accumulated_output_info = "";

    // get the message from the user also check if it is ASCII or hex
    get_value( inData, document.stuff.indata.value, document.stuff.intype[0].checked );

    // problems??
    if ( inData[0] == ERROR_VAL ) {
        document.stuff.details.value = accumulated_output_info;
        return;
    }
    accumulate_bitstring( "★输入 bits:", inData, 8 );

    // get the key from the user
    get_value( Key, document.stuff.key.value, false );
    // problems??
    if ( Key[0] == ERROR_VAL ) {
        document.stuff.details.value = accumulated_output_info;
        return;
    }
    accumulate_bitstring( "★** bits:", Key, 8 );

    // do the encryption/decryption, put output in DES_output for display
    DES_output = des_encrypt( inData, Key, do_encrypt )

    accumulate_bitstring ("★输出 bits:", DES_output, 8 );

    // process output
    format_DES_output( );
    document.stuff.details.value = accumulated_output_info;
}

// do Triple-DES encrytion/decryption
// do_encrypt is TRUE for encrypt, FALSE for decrypt
function do_tdes( do_encrypt ) {
   var inData = new Array( 65 );    // input message bits
   var tempdata = new Array( 65 );    // interm result bits
   var KeyA = new Array( 65 );
   var KeyB = new Array( 65 );

   accumulated_output_info = "";

   // get the message from the user
   // also check if it is ASCII or hex
   get_value( inData, document.stuff.indata.value,
        document.stuff.intype[0].checked );

   // problems??
   if ( inData[0] == ERROR_VAL )
   {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_bitstring( "Input bits:", inData, 8 );

   // get the key part A from the user
   get_value( KeyA, document.stuff.key.value, false );
   // problems??
   if ( KeyA[0] == ERROR_VAL )
   {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_bitstring( "Key A bits:", KeyA, 8 );


   // get the key part B from the user
   get_value( KeyB, document.stuff.keyb.value, false );
   // problems??
   if ( KeyB[0] == ERROR_VAL )
   {
      document.stuff.details.value = accumulated_output_info;
      return;
   }
   accumulate_bitstring( "Key B bits:", KeyB, 8 );

   if ( do_encrypt )
   {
      // TDES encrypt = DES encrypt/decrypt/encrypt
      accumulate_output("---- Starting first encryption ----");
      tempdata = des_encrypt( inData, KeyA, true );
      accumulate_output("---- Starting second decryption ----");
      tempdata = des_encrypt( tempdata, KeyB, false );
      accumulate_output("---- Starting third encryption ----");
      DES_output = des_encrypt( tempdata, KeyA, true );
   }
   else
   {
      // TDES decrypt = DES decrypt/encrypt/decrypt
      accumulate_output("---- Starting first decryption ----");
      tempdata = des_encrypt( inData, KeyA, false );
      accumulate_output("---- Starting second encryption ----");
      tempdata = des_encrypt( tempdata, KeyB, true );
      accumulate_output("---- Starting third decryption ----");
      DES_output = des_encrypt( tempdata, KeyA, false );
   }

   accumulate_bitstring ("Output ", DES_output, 8 );

   // process output
   format_DES_output( );
   document.stuff.details.value = accumulated_output_info;
}

【加密解密】数据加密标准DES加密(Javascript实现)

DES算法提供CBC, OFB, CFB, ECB四种模式,MAC是基于ECB实现的。

一、数据补位

DES数据加解密就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节(通常补00或者FF,根据实际要求不同)进行计算,之后按照顺序将计算所得的数据连在一起即可。

这里有个问题就是为什么要进行数据补位?主要原因是DES算法加解密时要求数据必须为8个字节。

二、ECB模式

DES ECB(电子密本方式)其实非常简单,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

三、CBC模式

DES CBC(密文分组链接方式)有点麻烦,它的实现机制使加密的各段数据之间有了联系。其实现的机理如下:

加密步骤如下:

1)首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,用指定的PADDING数据补位)

2)第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)

3)第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2

4)之后的数据以此类推,得到Cn

5)按顺序连为C1C2C3......Cn即为加密结果。

 

解密是加密的逆过程,步骤如下:

1)首先将数据按照8个字节一组进行分组得到C1C2C3......Cn

2)将第一组数据进行解密后与初始化向量I进行异或得到第一组明文D1(注意:一定是先解密再异或)

3)将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2

4)之后依此类推,得到Dn

5)按顺序连为D1D2D3......Dn即为解密结果。

这里注意一点,解密的结果并不一定是我们原来的加密数据,可能还含有你补得位,一定要把补位去掉才是你的原来的数据。

 

 DES的几种填补方式

   DES是对64位数据的加密算法,如数据位数不足64位的倍数,需要填充,补充到64位的倍数。

   NoPadding

   API或算法本身不对数据进行处理,加密数据由加密双方约定填补算法。例如若对字符串数据进行加解密,可以补充\0或者空格,然后trim

   PKCS5Padding

   加密前:数据字节长度对8取余,余数为m,若m>0,则补足8-m个字节,字节数值为8-m,即差几个字节就补几个字节,字节数值即为补充的字节数,若为0则补充8个字节的8

   解密后:取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文

  //KeyGenerator 提供对称**生成器的功能,支持各种算法
  private KeyGenerator ******;
  //SecretKey 负责保存对称**
  private SecretKey deskey;
  //Cipher负责完成加密或解密工作
  private Cipher c;
  //该字节数组负责保存加密的结果
  private byte[] cipherByte;

  /**
   * DesDemo
   * @throws NoSuchAlgorithmException
   * @throws NoSuchPaddingException
   */
  public DesDemo() throws NoSuchAlgorithmException, NoSuchPaddingException {
    Security.addProvider(new com.sun.crypto.provider.SunJCE());
    //实例化支持DES算法的**生成器(算法名称命名需按规定,否则抛出异常)
    ****** = KeyGenerator.getInstance("DES");
    //生成**
    deskey = ******.generateKey();
    System.out.println("**:" + UBytes.toHexString(deskey.getEncoded()));
    //生成Cipher对象,指定其支持的DES算法
    c = Cipher.getInstance("DES/ECB/NOPADDING");
    // c = Cipher.getInstance("DES/CBC/PKCS5Padding");
  }

  /**
   * 对字符串加密
   *
   * @param str
   * @return
   * @throws InvalidKeyException
   * @throws IllegalBlockSizeException
   * @throws BadPaddingException
   */
  public byte[] Encrytor(String str) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    // 根据**,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
    c.init(Cipher.ENCRYPT_MODE, deskey);
    byte[] src = str.getBytes();
    System.out.println("明文:" + UBytes.toHexString(src));
    // 加密,结果保存进cipherByte
    cipherByte = c.doFinal(src);
    System.out.println("密文:" + UBytes.toHexString(cipherByte));
    return cipherByte;
  }

  /**
   * 对字符串解密
   *
   * @param buff
   * @return
   * @throws InvalidKeyException
   * @throws IllegalBlockSizeException
   * @throws BadPaddingException
   */
  public byte[] Decryptor(byte[] buff) throws InvalidKeyException,
      IllegalBlockSizeException, BadPaddingException {
    // 根据**,对Cipher对象进行初始化,DECRYPT_MODE表示加密模式
    c.init(Cipher.DECRYPT_MODE, deskey);
    cipherByte = c.doFinal(buff);
    return cipherByte;
  }

  /**
   * main
   * @param args
   * @throws NoSuchPaddingException
   * @throws NoSuchAlgorithmException
   * @throws BadPaddingException
   * @throws IllegalBlockSizeException
   * @throws InvalidKeyException
   */
  public static void main(String[] args) throws Exception {
    DesDemo de1 = new DesDemo();
    String msg = "abcdefgh";
    byte[] encontent = de1.Encrytor(msg);
    byte[] decontent = de1.Decryptor(encontent);
    System.out.println("解密:" + UBytes.toHexString(decontent));

    System.out.println("明文是:" + msg);
    System.out.println("加密后:" + new String(encontent));
    System.out.println("解密后:" + new String(decontent));
}
**:F4 34 02 EA E9 37 EC 67 
明文:61 62 63 64 65 66 67 68 
密文:83 F7 08 EB 99 FF C3 4F 
解密:61 62 63 64 65 66 67 68 
明文是:abcdefgh
解密后:abcdefgh

 

转载于:https://my.oschina.net/dubenju/blog/834297