descore.java

来自「对称和非对称加密」· Java 代码 · 共 369 行

JAVA
369
字号
package com.dmgc.security.cipher.symmetic.des;

import java.security.InvalidKeyException;
import java.security.Key;
import java.io.*;

/**
 * <p>Title: DMGC SECURITY CIPHER LIB</p>
 * <p>Description: 上海信宁科技有限公司 安全密码库(JAVA version)</p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: 上海信宁科技有限公司</p>
 * DES核心算法
 * DES一个块是8个字节.密钥长度为8个字节,但是只有其中的56个比特使用,另外一个作为校验可以忽略.
 * <p>
 * DES算法可以经过了三十年的分析,并没有明显的缺点.唯一的缺陷就是密钥长度才56个比特,相对容易遭受强攻击.
 * <p>
 * 为了克服这个缺点,可使用三重DES方式来实现
 * <p>
 * DES 算法最初出IBM公司在1976发明.
 * <p>
 * @author 陆荣幸  周渊   潘勇
 * @version 1.0
 */

abstract public class DESCore {

  /////////////////////////////////////////////////////////////////////////////

  private static final int
      /**
       * DES加密解密轮数 16
       */
      ROUNDS = 16,
      /**
       * DES算法块大小
       */
      BLOCK_SIZE = 8,
      /**
       * DES密钥长度
       */
      KEY_LENGTH = 8,
      /**
       * DES可选长度
       */
      ALT_KEY_LENGTH = 7,
      /**
       * 在密钥方案中的元素数
       */
      INTERNAL_KEY_LENGTH = 2 * ROUNDS;

  /**
   * 密钥方案中的PC2置换表
   */
  private static final int[] SKB = new int[8 * 64];

  /**
   * 用于加密的S盒和置换表
   */
  private static final int SP_TRANS[] = new int[8 * 64];

  /**
   * 构建SKB和SP_TRANS表
   */
  static {

    String cd =
        "D]PKESYM`UBJ\\@RXA`I[T`HC`LZQ" + "\\PB]TL`[C`JQ@Y`HSXDUIZRAM`EK";
    int j, s, bit;
    int count = 0;
    int offset = 0;
    for (int i = 0; i < cd.length(); i++) {
      s = cd.charAt(i) - '@';
      if (s != 32) {
        bit = 1 << count++;
        for (j = 0; j < 64; j++)
          if ( (bit & j) != 0)
            SKB[offset + j] |= 1 << s;
        if (count == 6) {
          offset += 64;
          count = 0;
        }
      }
    }

    String spt =
        "g3H821:80:H03BA0@N1290BAA88::3112aIH8:8282@0@AH0:1W3A8P810@22;22" +
        "A18^@9H9@129:<8@822`?:@0@8PH2H81A19:G1@03403A0B1;:0@1g192:@919AA" +
        "0A109:W21492H@0051919811:215011139883942N8::3112A2:31981jM118::A" +
        "101@I88:1aN0<@030128:X;811`920:;H0310D1033@W980:8A4@804A3803o1A2" +
        "021B2:@1AH023GA:8:@81@@12092B:098042P@:0:A0HA9>1;289:@1804:40Ph=" +
        "1:H0I0HP0408024bC9P8@I808A;@0@0PnH0::8:19J@818:@iF0398:8A9H0<13@" +
        "001@11<8;@82B01P0a2989B:0AY0912889bD0A1@B1A0A0AB033O91182440A9P8" +
        "@I80n@1I03@1J828212A`A8:12B1@19A9@9@8^B:0@H00<82AB030bB840821Q:8" +
        "310A302102::A1::20A1;8";
    offset = 0;
    int k, c, param;
    for (int i = 0; i < 32; i++) { // each bit position
      k = -1; // pretend the -1th bit was set
      bit = 1 << i;
      for (j = 0; j < 32; j++) { // each set bit
        // Each character consists of two three-bit values:
        c = spt.charAt(offset >> 1) - '0' >> (offset & 1) * 3 & 7;
        offset++;
        if (c < 5) {
          // values 0...4 indicate a set bit 1...5 positions
          // from the previous set bit
          k += c + 1;
          SP_TRANS[k] |= bit;
          continue;
        }
        // other values take at least an additional parameter:
        // the next value in the sequence.
        param = spt.charAt(offset >> 1) - '0' >> (offset & 1) * 3 & 7;
        offset++;
        if (c == 5) {
          // indicates a bit set param+6 positions from
          // the previous set bit
          k += param + 6;
          SP_TRANS[k] |= bit;
        }
        else if (c == 6) {
          // indicates a bit set (param * 64) + 1 positions
          // from the previous set bit
          k += (param << 6) + 1;
          SP_TRANS[k] |= bit;
        }
        else {
          // indicates that we should skip (param * 64) positions,
          // then process the next value which will be in the range
          // 0...4.
          k += param << 6;
          j--;
        }
      }
    }
  }

//////////////////////////////////////////////////////////////////////////////
  /**
   * 内部密钥方案
   */
  private int[] sKey = new int[INTERNAL_KEY_LENGTH];
//////////////////////////////////////////////////////////////////////////////

  /**
   * 初始化算法
   * @param key 密钥
   * @param decrypt 加解密标志
   * @throws InvalidKeyException
   */
  protected void coreInit(Key key, boolean decrypt) throws InvalidKeyException {
    byte[] userkey = key.getEncoded();
    if (userkey == null)
      throw new InvalidKeyException("Null user key");

    if (userkey.length == ALT_KEY_LENGTH) {

      byte[] temp = new byte[KEY_LENGTH];

      temp[0] = (byte) (userkey[0]);
      temp[1] = (byte) (userkey[0] << 7 | userkey[1] >>> 1 & 0x7f);
      temp[2] = (byte) (userkey[1] << 6 | userkey[2] >>> 2 & 0x3f);
      temp[3] = (byte) (userkey[2] << 5 | userkey[3] >>> 3 & 0x1f);
      temp[4] = (byte) (userkey[3] << 4 | userkey[4] >>> 4 & 0x0f);
      temp[5] = (byte) (userkey[4] << 3 | userkey[5] >>> 5 & 0x07);
      temp[6] = (byte) (userkey[5] << 2 | userkey[6] >>> 6 & 0x03);
      temp[7] = (byte) (userkey[6] << 1);

      userkey = temp;
    }

    if (userkey.length != KEY_LENGTH)
      throw new InvalidKeyException("Invalid user key length");

    int i = 0;
    int c = (userkey[i++] & 0xFF) |
        (userkey[i++] & 0xFF) << 8 |
        (userkey[i++] & 0xFF) << 16 |
        (userkey[i++]) << 24;
    int d = (userkey[i++] & 0xFF) |
        (userkey[i++] & 0xFF) << 8 |
        (userkey[i++] & 0xFF) << 16 |
        (userkey[i]) << 24;

    int t = ( (d >>> 4) ^ c) & 0x0F0F0F0F;
    c ^= t;
    d ^= t << 4;
    t = ( (c << 18) ^ c) & 0xCCCC0000;
    c ^= t ^ t >>> 18;
    t = ( (d << 18) ^ d) & 0xCCCC0000;
    d ^= t ^ t >>> 18;
    t = ( (d >>> 1) ^ c) & 0x55555555;
    c ^= t;
    d ^= t << 1;
    t = ( (c >>> 8) ^ d) & 0x00FF00FF;
    d ^= t;
    c ^= t << 8;
    t = ( (d >>> 1) ^ c) & 0x55555555;
    c ^= t;
    d ^= t << 1;

    d = (d & 0x000000FF) << 16 |
        (d & 0x0000FF00) |
        (d & 0x00FF0000) >>> 16 |
        (c & 0xF0000000) >>> 4;
    c &= 0x0FFFFFFF;

    int s;
    int j = 0;

    for (i = 0; i < ROUNDS; i++) {
      if ( (0x7EFC >> i & 1) == 1) {
        c = (c >>> 2 | c << 26) & 0x0FFFFFFF;
        d = (d >>> 2 | d << 26) & 0x0FFFFFFF;
      }
      else {
        c = (c >>> 1 | c << 27) & 0x0FFFFFFF;
        d = (d >>> 1 | d << 27) & 0x0FFFFFFF;
      }
      s = SKB[c & 0x3F] |
          SKB[0x040 | ( ( (c >>> 6) & 0x03) | ( (c >>> 7) & 0x3C))] |
          SKB[0x080 | ( ( (c >>> 13) & 0x0F) | ( (c >>> 14) & 0x30))] |
          SKB[0x0C0 | ( ( (c >>> 20) & 0x01) | ( (c >>> 21) & 0x06)
                       | ( (c >>> 22) & 0x38))];
      t = SKB[0x100 | (d & 0x3F)] |
          SKB[0x140 | ( ( (d >>> 7) & 0x03) | ( (d >>> 8) & 0x3c))] |
          SKB[0x180 | ( (d >>> 15) & 0x3F)] |
          SKB[0x1C0 | ( ( (d >>> 21) & 0x0F) | ( (d >>> 22) & 0x30))];

      sKey[j++] = t << 16 | (s & 0x0000FFFF);
      s = s >>> 16 | (t & 0xFFFF0000);
      sKey[j++] = s << 4 | s >>> 28;
    }

    // Reverse the subkeys if we're decrypting
    // Best illustrated by example: 1 2 3 4 5 6 7 8  ->  7 8 5 6 3 4 1 2
    if (decrypt) {
      for (i = 0; i < 16; i++) {
        j = 30 - i + (i % 2 * 2);
        t = sKey[i];
        sKey[i] = sKey[j];
        sKey[j] = t;
      }
    }
  }

  /**
   * 执行加减密算法一块的核心实现
   * @param in   输入字节
   * @param inOffset  输入字节起始位置
   * @param out  输出字节
   * @param outOffset 输出字节起始位置
   */
  protected void coreCrypt(byte[] in, int inOffset, byte[] out, int outOffset) {
    int L = (in[inOffset++] & 0xFF) |
        (in[inOffset++] & 0xFF) << 8 |
        (in[inOffset++] & 0xFF) << 16 |
        (in[inOffset++]) << 24;
    int R = (in[inOffset++] & 0xFF) |
        (in[inOffset++] & 0xFF) << 8 |
        (in[inOffset++] & 0xFF) << 16 |
        (in[inOffset]) << 24;

    // Initial permutation
    int t = ( (R >>> 4) ^ L) & 0x0F0F0F0F;
    L ^= t;
    R ^= t << 4;
    t = ( (L >>> 16) ^ R) & 0x0000FFFF;
    R ^= t;
    L ^= t << 16;
    t = ( (R >>> 2) ^ L) & 0x33333333;
    L ^= t;
    R ^= t << 2;
    t = ( (L >>> 8) ^ R) & 0x00FF00FF;
    R ^= t;
    L ^= t << 8;
    t = ( (R >>> 1) ^ L) & 0x55555555;
    L ^= t;
    R ^= t << 1;

    // look! we fit all four variables (plus the class itself)
    // into short byte-codes!
    int u = R << 1 | R >>> 31;
    R = L << 1 | L >>> 31;
    L = u;

    for (int i = 0; i < INTERNAL_KEY_LENGTH; ) {
      u = R ^ sKey[i++];
      t = R ^ sKey[i++];
      t = t >>> 4 | t << 28;
      L ^= (SP_TRANS[0x040 | (t & 0x3F)] |
            SP_TRANS[0x0C0 | ( (t >>> 8) & 0x3F)] |
            SP_TRANS[0x140 | ( (t >>> 16) & 0x3F)] |
            SP_TRANS[0x1C0 | ( (t >>> 24) & 0x3F)] |
            SP_TRANS[u & 0x3F] |
            SP_TRANS[0x080 | ( (u >>> 8) & 0x3F)] |
            SP_TRANS[0x100 | ( (u >>> 16) & 0x3F)] |
            SP_TRANS[0x180 | ( (u >>> 24) & 0x3F)]);

      u = L ^ sKey[i++];
      t = L ^ sKey[i++];
      t = t >>> 4 | t << 28;
      R ^= (SP_TRANS[0x040 | (t & 0x3F)] |
            SP_TRANS[0x0C0 | ( (t >>> 8) & 0x3F)] |
            SP_TRANS[0x140 | ( (t >>> 16) & 0x3F)] |
            SP_TRANS[0x1C0 | ( (t >>> 24) & 0x3F)] |
            SP_TRANS[u & 0x3F] |
            SP_TRANS[0x080 | ( (u >>> 8) & 0x3F)] |
            SP_TRANS[0x100 | ( (u >>> 16) & 0x3F)] |
            SP_TRANS[0x180 | ( (u >>> 24) & 0x3F)]);
    }
    R = R >>> 1 | R << 31;
    L = L >>> 1 | L << 31;

    // Final permutation
    t = (R >>> 1 ^ L) & 0x55555555;
    L ^= t;
    R ^= t << 1;
    t = (L >>> 8 ^ R) & 0x00FF00FF;
    R ^= t;
    L ^= t << 8;
    t = (R >>> 2 ^ L) & 0x33333333;
    L ^= t;
    R ^= t << 2;
    t = (L >>> 16 ^ R) & 0x0000FFFF;
    R ^= t;
    L ^= t << 16;
    t = (R >>> 4 ^ L) & 0x0F0F0F0F;

    L ^= t;
    R ^= (t << 4);

    out[outOffset++] = (byte) (L);
    out[outOffset++] = (byte) (L >> 8);
    out[outOffset++] = (byte) (L >> 16);
    out[outOffset++] = (byte) (L >> 24);
    out[outOffset++] = (byte) (R);
    out[outOffset++] = (byte) (R >> 8);
    out[outOffset++] = (byte) (R >> 16);
    out[outOffset] = (byte) (R >> 24);
  }

  /////////////////////////////////////////////////////////////////////////////
  /**
   * 加密文件
   * @param inFile 输入文件 由路径与文件名构成
   * @param outFile 输出文件 由路径与文件名构成
   * @param keys 密钥,由字符串构成 十六进制形式
   */
  abstract public void Encrypt(String inFile, String outFile, String keys) throws
      FileNotFoundException, InvalidKeyException, IOException, Exception;

  /**
   * 解密文件
   * @param inFile 输入文件 由路径与文件名构成
   * @param outFile 输出文件 由路径与文件名构成
   * @param keys 密钥,由字符串构成 十六进制形式
   */

  abstract public void Decrypt(String inFile, String outFile, String keys) throws
      FileNotFoundException, InvalidKeyException, IOException, Exception;

  /**
   * 构造函数
   */
  public DESCore() {
  }

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?