DES单元

//Delphi version
//ZswangY37, October 2006
//
//THIS SOFTWARE IS PROVIDED "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//SUCH DAMAGE.

unit DESUtils;

interface

type
  TDesKey = array of Longword;
 
function des_createKeys(key: string): TDesKey;
function des(key: string; message: string;
  encrypt: Boolean; mode: Boolean; iv: string): string;

implementation

//设计 Zswang 2006-10-26 wjhu111#21cn.com 尊重作者,转贴请注明出处

//des_createKeys
//this takes as input a 64 bit key (even though only 56 bits are used)
//as an array of 2 integers, and returns 16 48 bit keys
function des_createKeys(key: string): TDesKey;
const
  //declaring this locally speeds things up a bit
  pc2bytes0: array[0..15] of Integer = (0, $4, $20000000, $20000004, $10000,
    $10004, $20010000, $20010004, $200, $204, $20000200, $20000204, $10200,
    $10204, $20010200, $20010204);
  pc2bytes1: array[0..15] of Integer = (0, $1, $100000, $100001, $4000000,
    $4000001, $4100000, $4100001, $100, $101, $100100, $100101, $4000100,
    $4000101, $4100100, $4100101);
  pc2bytes2: array[0..15] of Integer = (0, $8, $800, $808, $1000000, $1000008,
    $1000800, $1000808, 0, $8, $800, $808, $1000000, $1000008, $1000800,
    $1000808);
  pc2bytes3: array[0..15] of Integer = (0, $200000, $8000000, $8200000, $2000,
    $202000, $8002000, $8202000, $20000, $220000, $8020000, $8220000, $22000,
    $222000, $8022000, $8222000);
  pc2bytes4: array[0..15] of Integer = (0, $40000, $10, $40010, 0, $40000, $10,
    $40010, $1000, $41000, $1010, $41010, $1000, $41000, $1010, $41010);
  pc2bytes5: array[0..15] of Integer = (0, $400, $20, $420, 0, $400, $20, $420,
    $2000000, $2000400, $2000020, $2000420, $2000000, $2000400, $2000020,
    $2000420);
  pc2bytes6: array[0..15] of Integer = (0, $10000000, $80000, $10080000, $2,
    $10000002, $80002, $10080002, 0, $10000000, $80000, $10080000, $2,
    $10000002, $80002, $10080002);
  pc2bytes7: array[0..15] of Integer = (0, $10000, $800, $10800, $20000000,
    $20010000, $20000800, $20010800, $20000, $30000, $20800, $30800, $20020000,
    $20030000, $20020800, $20030800);
  pc2bytes8: array[0..15] of Integer = (0, $40000, 0, $40000, $2, $40002, $2,
    $40002, $2000000, $2040000, $2000000, $2040000, $2000002, $2040002,
    $2000002, $2040002);
  pc2bytes9: array[0..15] of Integer = (0, $10000000, $8, $10000008, 0,
    $10000000, $8, $10000008, $400, $10000400, $408, $10000408, $400, $10000400,
    $408, $10000408);
  pc2bytes10: array[0..15] of Integer = (0, $20, 0, $20, $100000, $100020,
    $100000, $100020, $2000, $2020, $2000, $2020, $102000, $102020, $102000,
    $102020);
  pc2bytes11: array[0..15] of Integer = (0, $1000000, $200, $1000200, $200000,
    $1200000, $200200, $1200200, $4000000, $5000000, $4000200, $5000200,
    $4200000, $5200000, $4200200, $5200200);
  pc2bytes12: array[0..15] of Integer = (0, $1000, $8000000, $8001000, $80000,
    $81000, $8080000, $8081000, $10, $1010, $8000010, $8001010, $80010, $81010,
    $8080010, $8081010);
  pc2bytes13: array[0..15] of Integer = (0, $4, $100, $104, 0, $4, $100, $104,
  $1, $5, $101, $105, $1, $5, $101, $105);
  shifts: array[0..15] of Boolean = (False, False, True, True, True, True, True,
    True, False, True, True, True, True, True, True, False);
var
  //other variables
  iterations: Longword;
  lefttemp, righttemp: Longword;
  m, n, temp: Longword;
  i, j: Longword;
  left, right: Longword;
begin
  //how many iterations (1 for des, 3 for triple des)
  if Length(key) >= 24 then
    iterations := 3
  else iterations := 1;
  //stores the return keys
  SetLength(Result, 32 * iterations);
  //now define the left shifts which need to be done
  m := 1;
  n := 0;
  for j := 1 to iterations do //either 1 or 3 iterations
  begin
    left := (Ord(Key[m]) shl 24) or (Ord(Key[m + 1]) shl 16) or
      (Ord(Key[m + 2]) shl 8) or Ord(Key[m + 3]);
    Inc(m, 4);
    right := (Ord(Key[m]) shl 24) or (Ord(Key[m + 1]) shl 16) or
      (Ord(Key[m + 2]) shl 8) or Ord(Key[m + 3]);
    Inc(m, 4);

    temp := ((left shr 4) xor right) and $0f0f0f0f;
    right := right xor temp;
    left := left xor (temp shl 4);
    temp := ((Int64(right) shr -16) xor left) and $0000ffff;
    left := left xor temp;
    right := right xor Longword(Int64(temp) shl -16);
    temp := ((left shr 2) xor right) and $33333333;
    right := right xor temp;
    left := left xor (temp shl 2);
    temp := ((Int64(right) shr -16) xor left) and $0000ffff;
    left := left xor temp;
    right := right xor Longword(Int64(temp) shl -16);
    temp := ((left shr 1) xor right) and $55555555;
    right := right xor temp;
    left := left xor (temp shl 1);
    temp := ((right shr 8) xor left) and $00ff00ff;
    left := left xor temp;
    right := right xor (temp shl 8);
    temp := ((left shr 1) xor right) and $55555555;
    right := right xor temp;
    left := left xor (temp shl 1);

    //the right side needs to be shifted and to get the last four bits of the left side
    temp := (left shl 8) or ((right shr 20) and $000000f0);
    //left needs to be put upside down
    left := (right shl 24) or ((right shl 8) and $ff0000) or ((right shr 8) and $ff00) or ((right shr 24) and $f0);


    right := temp;

    //now go through and perform these shifts on the left and right Result
    for i := Low(shifts) to High(shifts) do
    begin
      //shift the Result either one or two bits to the left
      if shifts[i] then
      begin
        left := (left shl 2) or (left shr 26);
        right := (right shl 2) or (right shr 26);
      end else
      begin
        left := (left shl 1) or (left shr 27);
        right := (right shl 1) or (right shr 27);
      end;
      left := left and -$f;
      right := right and -$f;

      //now apply PC-2, in such a way that E is easier when encrypting or decrypting
      //this conversion will look like PC-2 except only the last 6 bits of each byte are used
      //rather than 48 consecutive bits and the order of lines will be according to
      //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
      lefttemp := pc2bytes0[left shr 28] or pc2bytes1[(left shr 24) and $f] or
        pc2bytes2[(left shr 20) and $f] or pc2bytes3[(left shr 16) and $f] or
        pc2bytes4[(left shr 12) and $f] or pc2bytes5[(left shr 8) and $f] or
        pc2bytes6[(left shr 4) and $f];
      righttemp := pc2bytes7[right shr 28] or pc2bytes8[(right shr 24) and $f]
        or pc2bytes9[(right shr 20) and $f] or pc2bytes10[(right shr 16) and $f]
        or pc2bytes11[(right shr 12) and $f] or pc2bytes12[(right shr 8) and $f]
        or pc2bytes13[(right shr 4) and $f];
      temp := ((righttemp shr 16) xor lefttemp) and $0000ffff;
      Result[n] := lefttemp xor temp;
      Inc(n);
      Result[n] := Integer(righttemp xor (temp shl 16));
      Inc(n);
    end;
  end; //for each iterations
end; //end of des_createKeys

//des
//this takes the key, the message, and whether to encrypt or decrypt
function des(key: string; message: string; encrypt: Boolean;
  mode: Boolean; iv: string): string;
const
  //declaring this locally speeds things up a bit
  spfunction1: array[0..63] of Integer = ($1010400, 0, $10000, $1010404,
    $1010004, $10404, $4, $10000, $400, $1010400, $1010404, $400, $1000404,
    $1010004, $1000000, $4, $404, $1000400, $1000400, $10400, $10400, $1010000,
    $1010000, $1000404, $10004, $1000004, $1000004, $10004, 0, $404, $10404,
    $1000000, $10000, $1010404, $4, $1010000, $1010400, $1000000, $1000000,
    $400, $1010004, $10000, $10400, $1000004, $400, $4, $1000404, $10404,
    $1010404, $10004, $1010000, $1000404, $1000004, $404, $10404, $1010400,
    $404, $1000400, $1000400, 0, $10004, $10400, 0, $1010004);
  spfunction2: array[0..63] of Integer = (-$7fef7fe0, -$7fff8000, $8000,
    $108020, $100000, $20, -$7fefffe0, -$7fff7fe0, -$7fffffe0, -$7fef7fe0,
    -$7fef8000, -$80000000, -$7fff8000, $100000, $20, -$7fefffe0, $108000,
    $100020, -$7fff7fe0, 0, -$80000000, $8000, $108020, -$7ff00000, $100020,
    -$7fffffe0, 0, $108000, $8020, -$7fef8000, -$7ff00000, $8020, 0, $108020,
    -$7fefffe0, $100000, -$7fff7fe0, -$7ff00000, -$7fef8000, $8000, -$7ff00000,
    -$7fff8000, $20, -$7fef7fe0, $108020, $20, $8000, -$80000000, $8020,
    -$7fef8000, $100000, -$7fffffe0, $100020, -$7fff7fe0, -$7fffffe0, $100020,
    $108000, 0, -$7fff8000, $8020, -$80000000, -$7fefffe0, -$7fef7fe0, $108000);
  spfunction3: array[0..63] of Integer = ($208, $8020200, 0, $8020008, $8000200,
    0, $20208, $8000200, $20008, $8000008, $8000008, $20000, $8020208, $20008,
    $8020000, $208, $8000000, $8, $8020200, $200, $20200, $8020000, $8020008,
    $20208, $8000208, $20200, $20000, $8000208, $8, $8020208, $200, $8000000,
    $8020200, $8000000, $20008, $208, $20000, $8020200, $8000200, 0, $200,
    $20008, $8020208, $8000200, $8000008, $200, 0, $8020008, $8000208, $20000,
    $8000000, $8020208, $8, $20208, $20200, $8000008, $8020000, $8000208, $208,
    $8020000, $20208, $8, $8020008, $20200);
  spfunction4: array[0..63] of Integer = ($802001, $2081, $2081, $80, $802080,
    $800081, $800001, $2001, 0, $802000, $802000, $802081, $81, 0, $800080,
    $800001, $1, $2000, $800000, $802001, $80, $800000, $2001, $2080, $800081,
    $1, $2080, $800080, $2000, $802080, $802081, $81, $800080, $800001, $802000,
    $802081, $81, 0, 0, $802000, $2080, $800080, $800081, $1, $802001, $2081,
    $2081, $80, $802081, $81, $1, $2000, $800001, $2001, $802080, $800081,
    $2001, $2080, $800000, $802001, $80, $800000, $2000, $802080);
  spfunction5: array[0..63] of Integer = ($100, $2080100, $2080000, $42000100,
    $80000, $100, $40000000, $2080000, $40080100, $80000, $2000100, $40080100,
    $42000100, $42080000, $80100, $40000000, $2000000, $40080000, $40080000, 0,
    $40000100, $42080100, $42080100, $2000100, $42080000, $40000100, 0,
    $42000000, $2080100, $2000000, $42000000, $80100, $80000, $42000100, $100,
    $2000000, $40000000, $2080000, $42000100, $40080100, $2000100, $40000000,
    $42080000, $2080100, $40080100, $100, $2000000, $42080000, $42080100,
    $80100, $42000000, $42080100, $2080000, 0, $40080000, $42000000, $80100,
    $2000100, $40000100, $80000, 0, $40080000, $2080100, $40000100);
  spfunction6: array[0..63] of Integer = ($20000010, $20400000, $4000,
    $20404010, $20400000, $10, $20404010, $400000, $20004000, $404010, $400000,
    $20000010, $400010, $20004000, $20000000, $4010, 0, $400010, $20004010,
    $4000, $404000, $20004010, $10, $20400010, $20400010, 0, $404010, $20404000,
    $4010, $404000, $20404000, $20000000, $20004000, $10, $20400010, $404000,
    $20404010, $400000, $4010, $20000010, $400000, $20004000, $20000000, $4010,
    $20000010, $20404010, $404000, $20400000, $404010, $20404000, 0, $20400010,
    $10, $4000, $20400000, $404010, $4000, $400010, $20004010, 0, $20404000,
    $20000000, $400010, $20004010);
  spfunction7: array[0..63] of Integer = ($200000, $4200002, $4000802, 0, $800,
    $4000802, $200802, $4200800, $4200802, $200000, 0, $4000002, $2, $4000000,
    $4200002, $802, $4000800, $200802, $200002, $4000800, $4000002, $4200000,
    $4200800, $200002, $4200000, $800, $802, $4200802, $200800, $2, $4000000,
    $200800, $4000000, $200800, $200000, $4000802, $4000802, $4200002, $4200002,
    $2, $200002, $4000000, $4000800, $200000, $4200800, $802, $200802, $4200800,
    $802, $4000002, $4200802, $4200000, $200800, 0, $2, $4200802, 0, $200802,
    $4200000, $800, $4000002, $4000800, $800, $200002);
  spfunction8: array[0..63] of Integer = ($10001040, $1000, $40000, $10041040,
    $10000000, $10001040, $40, $10000000, $40040, $10040000, $10041040, $41000,
    $10041000, $41040, $1000, $40, $10040000, $10000040, $10001000, $1040,
    $41000, $40040, $10040040, $10041000, $1040, 0, 0, $10040040, $10000040,
    $10001000, $41040, $40000, $41040, $40000, $10041000, $1000, $40, $10040040,
    $1000, $41040, $10001000, $40, $10000040, $10040000, $10040040, $10000000,
    $40000, $10001040, 0, $10041040, $40040, $10000040, $10040000, $10001000,
    $10001040, 0, $10041040, $41000, $41000, $1040, $1040, $40040, $10000000,
    $10041000);
var
  keys: TDesKey;
  m, i, j: Longword;
  temp, temp2, right1, right2, left, right: Longword;
  looping: array of Integer;
  cbcleft, cbcleft2, cbcright, cbcright2: Longword;
  endloop, loopinc: Longword;
  len: Longword;
  chunk: Longword;
  iterations: Longword;
  tempresult: string;
begin
  keys := des_createKeys(key);
  len := Length(message);
  chunk := 0;
  cbcleft2 := 0;
  cbcright2 := 0;
  cbcleft := 0;
  cbcright := 0;
  //set up the loops for single and triple des
  if Length(Keys) = 32 then
    iterations := 3
  else iterations := 9;
  if (iterations = 3) then
  begin
    SetLength(looping, 3);
    if encrypt then
    begin
      looping[0] := 0;
      looping[1] := 32;
      looping[2] := 2;
    end else
    begin
      looping[0] := 30;
      looping[1] := -2;
      looping[2] := -2;
    end;
  end else
  begin
    SetLength(looping, 9);
    if encrypt then
    begin
      looping[0] := 0;
      looping[1] := 32;
      looping[2] := 2;

      looping[3] := 62;
      looping[4] := 30;
      looping[5] := -2;

      looping[6] := 64;
      looping[7] := 96;
      looping[8] := 2;
    end else
    begin
      looping[0] := 94;
      looping[1] := 62;
      looping[2] := -2;

      looping[3] := 32;
      looping[4] := 64;
      looping[5] := 2;

      looping[6] := 30;
      looping[7] := -2;
      looping[8] := -2;
    end;
  end;
  message := message + #0#0#0#0#0#0#0#0; //pad the message out with null bytes
  //store the result here
  Result := '';
  tempresult := '';
  m := 1;
  if mode then //CBC mode
  begin
    cbcleft := (Ord(iv[m]) shl 24) or (Ord(iv[m + 1]) shl 16) or
      (Ord(iv[m + 2]) shl 8) or Ord(iv[m + 3]);
    cbcright := (Ord(iv[m]) shl 24) or (Ord(iv[m + 1]) shl 16) or
      (Ord(iv[m + 2]) shl 8) or Ord(iv[m + 3]);
    m := 1;
  end;

  //loop through each 64 bit chunk of the message
  while m <= len do
  begin
    left := (Ord(message[m]) shl 24) or (Ord(message[m + 1]) shl 16) or
      (Ord(message[m + 2]) shl 8) or Ord(message[m + 3]);
    Inc(m, 4);
    right := (Ord(message[m]) shl 24) or (Ord(message[m + 1]) shl 16) or
      (Ord(message[m + 2]) shl 8) or Ord(message[m + 3]);
    Inc(m, 4);

    //for Cipher Block Chaining mode, xor the message with the previous result
    if mode then
    begin
      if encrypt then
      begin
        left := left xor cbcleft;
        right := right xor cbcright;
      end else
      begin
        cbcleft2 := cbcleft;
        cbcright2 := cbcright;
        cbcleft := left;
        cbcright := right;
      end;
    end;
    //first each 64 but chunk of the message must be permuted according to IP
    temp := ((left shr 4) xor right) and $0f0f0f0f;
    right := right xor temp;
    left := left xor (temp shl 4);
    temp := ((left shr 16) xor right) and $0000ffff;
    right := right xor temp;
    left := left xor (temp shl 16);
    temp := ((right shr 2) xor left) and $33333333;
    left := left xor temp;
    right := right xor (temp shl 2);
    temp := ((right shr 8) xor left) and $00ff00ff;
    left := left xor temp;
    right := right xor (temp shl 8);
    temp := ((left shr 1) xor right) and $55555555;
    right := right xor temp;
    left := left xor (temp shl 1);

    left := ((left shl 1) or (left shr 31));
    right := ((right shl 1) or (right shr 31));

    //do this either 1 or 3 times for each chunk of the message
    j := 0;
    while j < iterations do
    begin
      endloop := looping[j + 1];
      loopinc := looping[j + 2];
      //now go through and perform the encryption or decryption
      i := looping[j];
      while i <> endloop do
      begin
        right1 := right xor keys[i];
        right2 := ((right shr 4) or (right shl 28)) xor keys[i + 1];
        //the result is attained by passing these bytes through the S selection functions
        temp := left;
        left := right;
        right := temp xor Longword(spfunction2[(right1 shr 24) and $3f] or
          spfunction4[(right1 shr 16) and $3f] or
          spfunction6[(right1 shr 8) and $3f] or spfunction8[right1 and $3f] or
          spfunction1[(right2 shr 24) and $3f] or
          spfunction3[(right2 shr 16) and $3f] or
          spfunction5[(right2 shr 8) and $3f] or spfunction7[right2 and $3f]);
        i := i + loopinc; //for efficiency
      end;
      temp := left;
      left := right;
      right := temp; //unreverse left and right
      Inc(j, 3);
    end; //for either 1 or 3 iterations

    //move then each one bit to the right
    left := ((left shr 1) or (left shl 31));
    right := ((right shr 1) or (right shl 31));

    //now perform IP-1, which is IP in the opposite direction
    temp := ((left shr 1) xor right) and $55555555;
    right := right xor temp;
    left := left xor (temp shl 1);
    temp := ((right shr 8) xor left) and $00ff00ff;
    left := left xor temp;
    right := right xor (temp shl 8);
    temp := ((right shr 2) xor left) and $33333333;
    left := left xor temp;
    right := right xor (temp shl 2);
    temp := ((left shr 16) xor right) and $0000ffff;
    right := right xor temp;
    left := left xor (temp shl 16);
    temp := ((left shr 4) xor right) and $0f0f0f0f;
    right := right xor temp;
    left := left xor (temp shl 4);

    //for Cipher Block Chaining mode, xor the message with the previous result
    if (mode) then
    begin
      if (encrypt) then
      begin
        cbcleft := left;
        cbcright := right;
      end else
      begin
        left := left xor cbcleft2;
        right := right xor cbcright2;
      end;
    end;
    tempresult := tempresult + Char(left shr 24) + Char((left shr 16) and $ff) +
       Char(left shr 8 and $ff) + Char(left and $ff) + Char(right shr 24) +
       Char((right shr 16) and $ff) + Char((right shr 8) and $ff) +
       Char(right and $ff);

    chunk := chunk + 8;
    if chunk = 512 then
    begin
      Result := Result + tempresult;
      tempresult := '';
      chunk := 0;
    end;
  end; //for every 8 characters, or 64 bits in the message

  //return the result as an array
  Result := Result + tempresult;
end; //end of des

end. 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值