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

基于JavaScript的DES算法加密解密实现(源码)

程序员文章站 2022-03-01 17:27:02
...

文章目录

DES实现

ByteUtil

ByteUtil.js,用于通用的字节处理,DESUtil.js需要使用其中的部分方法

// 左移
export let left_move = (text, number) => {
  if (text == null) {
    return null;
  }
  let result = "";
  for (let i = number; i < text.length; i++) {
    result += text.charAt(i);
  }
  for (let i = 0; i < number; i++) {
    result += text.charAt(i);
  }
  return result;
}

// 将字符串转化为ASCII
export let to_8binary = (text) => {
  if (text == null) {
    return null;
  }
  let binary = "";
  for (let i = 0; i < text.length; i++) {
    let charCode = text.charCodeAt(i);
    if (charCode > 255) {
      throw new SyntaxError;
    }
    binary += charCode.toString(2).padStart(8, '0');
  }
  return binary;
}

// 将字符串转化为4位二进制格式,比如to_4binary(13)=00010011
export let to_4binary = (text) => {
  if (text == null) {
    return null;
  }
  let binary = "";
  for (let i = 0; i < text.length; i++) {
    let charCode = parseInt(text.charAt(i), 16).toString(2);
    binary += charCode.padStart(4, '0');
  }
  return binary;
}

/**
 * 将二进制字符串转成16进制
 * @param bin
 * @returns {string}
 */
let bin_to_hex = (bin) => {
  return parseInt(bin, 2).toString(16);
}

// 将10进制换成4位二进制
export let decimal_to_binary = (hex) => {
  let charCode = parseInt(hex, 10).toString(2);
  return charCode.padStart(4, '0');
}

export let binary_to_hex = (binary) => {
  let result = "";
  for (let i = 0; i < binary.length; i += 4) {
    result += parseInt(binary.substr(i, 4), 2).toString(16);
  }
  return result;
}

/**
 * 二进制异或
 * @param x 二进制输入X
 * @param y 二进制输入Y
 * @returns {string}
 */
let xor_bin = (x, y) => {
  let result = "";
  for (let i = 0; i < x.length; i++) {
    if (String(x).charAt(i) === String(y).charAt(i)) {
      result += "0";
    } else {
      result += "1";
    }
  }
  return result;
}

/**
 * 两位16进制进行异或
 * @param hexA 两位16进制字符串A
 * @param hexB 两位16进制字符串B
 * @returns {string}
 */
export let xor_hex = (hexA, hexB) => {
  let result = "";
  // 先将16进制字符串转换成二进制
  let binaryA = to_4binary(hexA);
  let binaryB = to_4binary(hexB);
  // 对二进制进行异或
  result = xor_bin(binaryA, binaryB);
  // 将异或结果转成16进制
  return bin_to_hex(result).padStart(2, '0');
}

/**
 * 多位16进制进行异或计算
 * @param hexA
 * @param hexB
 * @returns {string}
 */
export let xor_hex_fill = (hexA, hexB) => {
  let len = hexA.length > hexB.length ? hexA.length : hexB.length;
  let result = '';
  for (let i = 0; i < len; i += 2) {
    result += xor_hex(hexA.substr(i, 2), hexB.substr(i, 2));
  }
  return result;
}

DESUtil

用于DES算法的加密解密实现工具类。

import { left_move, to_8binary, to_4binary, decimal_to_binary, binary_to_hex,  } from "./ByteUtil";

// pc置换表1 将64位**置换成56位
let pc_table_1 = [
  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,
  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,
];

// pc置换表2 将56位子**置换成48位
let pc_table_2 = [
  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
];

// ip置换表
let ip_table = [
  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
];

// 将32位映射为48位表
let e_table = [
  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
];

// 8个S盒
let s_tables = [
  [
    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, 10, 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
  ]
]

// p表
let p_table = [
  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
];

// ip逆置换表
let ip_inverse_table = [
  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,
];

// 计算子**的旋转次数
let rotations = [
  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
];

/**
 * **pc置换,将64位**通过ip表转化为56位
 * @param key 指定的**,只会读取其中64位
 * @returns {string|null} 为null时返回null,其它时候返回56位数据
 */
let pc_substitution = (key) => {
  if (key == null) {
    return null;
  }
  let result = "";
  for (let i in pc_table_1) {
    result += key.charAt(pc_table_1[i] - 1);
  }
  return result;
}

/**
 * 获取子**表
 * @param compressedKey 56位压缩**
 * @returns {null|[]} 16个56位子**数组
 */
let sub_key_table = (compressedKey) => {
  if (compressedKey == null) {
    return null;
  }
  let C_temp = compressedKey.substr(0, 28);
  let D_temp = compressedKey.substr(28, 28);
  let result = [];
  for (let i = 0; i < rotations.length; i++) {
    C_temp = left_move(C_temp, rotations[i]);
    D_temp = left_move(D_temp, rotations[i]);
    result.push(C_temp + D_temp + '\n');
  }
  return result;
}

/**
 * 获取被压缩后的子**表
 * 将16个56位子**压缩成48位子**
 * @param sub_table 16位子**表
 * @returns {null|[]} 16位48位子**数组
 */
let sub_key_table_compress = (sub_table) => {
  if (sub_table == null) {
    return null;
  }
  let result = [];
  for (let i = 0; i < sub_table.length; i++) {
    let temp = "";
    // pc2置换
    for (let j in pc_table_2) {
      temp += String(sub_table[i]).charAt(pc_table_2[j] - 1);
    }
    result.push(temp + '\n');
  }
  return result;
}

/**
 * e盒置换
 * @param text
 * @returns {string}
 */
let e = (text) => {
  if (text.length !== 32) {
    throw new Error("e函数的参数长度不为32位")
  }
  let result = "";
  for (let i in e_table) {
    result += text.charAt(e_table[i] - 1);
  }
  return result;
}

// 手动异或函数
let xor = (x, y) => {
  let result = "";
  for (let i = 0; i < x.length; i++) {
    if (String(x).charAt(i) === String(y).charAt(i)) {
      result += "0";
    } else {
      result += "1";
    }
  }
  return result;
}

// 将text按number位数切割成一个数组
let division = (text, number) => {
  let result = [];
  let temp = "";
  for (let i = 0; i < text.length; i++) {
    if (i !== 0 && i % number === 0) {
      result.push(temp);
      temp = "";
    }
    temp += text[i];
  }
  result.push(temp);
  return result;
}

/*
* 将48位的text分成8个6位的数,
* 然后将每个6位数的第一位和第六位组成S盒的行数,
* 中间四位组成S盒的列数,
* 然后获取到一个四位的数,
* 最后组合8个S盒的数,并通过p置换返回一个32位的文本
*
* */
let s = (text) => {
  let table = division(text, 6);
  let result = "";
  for (let i = 0; i < s_tables.length; i++) {
    let row = table[i].charAt(0) + table[i].charAt(5);
    let column = table[i].substr(1, 4);
    row = parseInt(row, 2);
    column = parseInt(column, 2);
    let temp = s_tables[i][row * 16 + column];
    temp = decimal_to_binary(temp);
    result += temp;
  }
  let p_temp = "";
  for (let i in p_table) {
    p_temp += result.charAt(p_table[i] - 1);
  }
  return p_temp;
}

// f轮函数
let f = (R, K) => {
  let E_R = e(R);
  let temp = xor(E_R, K);
  // 进行s盒替换
  return s(temp);
}

// 明文ip置换
let ip_substitution = (text) => {
  if (text == null) {
    return null;
  }
  let result = "";
  for (let i in ip_table) {
    result += text.charAt(ip_table[i] - 1);
  }
  return result;
}

// ip逆置换
let ip_inverse_substitution = (text) => {
  if (text == null) {
    return null;
  }
  let result = "";
  for (let i in ip_inverse_table) {
    result += text.charAt(ip_inverse_table[i] - 1);
  }
  return result;
}

/**
 * des通过明文和**加密
 * 明文 **都为64位
 *
 * 加密流程:
 * **部分
 * 1、将64位**通过pc1置换成56位**
 * 2、用56位**移位生成16个56位子**
 * 3、将16个56位子**通过pc2置换成16个48位子**,等待加密时使用(K1,K2,K3...)
 *
 * 加密部分
 * 1、将64位明文进行ip置换
 * 2、截取前32位为L0, 后32位为R0
 * 3、进行轮运算
 *    第一轮
 *      L1 = R0
 *      R1 = L0 ^ f(R0, K1)
 *    第二轮
 *      L2 = R1
 *      R2 = L1 ^ f(R1, K2)
 *    ...
 *    f为 f(R, K)
 *      {
 *        let E_R = e(R);
 *        let temp = xor(E_R, K);
 *        return s(temp);
 *      }
 *      首先将32位的R扩展成48位,
 *      然后将48位的R和48位K进行异或,
 *      最后进行S盒替换,变成32位的文本。
 *    f为 S(text)
 *      首先将48位的text分割成8个6位的数,
 *      然后每个6位的数对应一个S盒,
 *      将6位数的第一位和第六位组成行号,中间四位组成列号,置换成相应S盒的数,
 *      然后按S0S1S2...变成32的文本输出
 * 4、将16轮变化后的L16,R16变成R16L16
 * 5、对R16L16进行ip逆置换
 * */
let des_encrypt = (text, key) => {
  if (text === null || key === null) {
    return "文本或**为空";
  }
  // 十六进制文本,故64位时长度为16
  if (text.length < 16 || key.length < 16) {
    return "长度不足64位"
  }
  let binaryKey = to_4binary(key);
  // 压缩64位**到56位
  let compressedKey = pc_substitution(binaryKey);
  // 生成16个56位子**
  let subKeyTable = sub_key_table(compressedKey);
  // 通过pc2置换生成16个48位子**
  let subKeyCompressTable = sub_key_table_compress(subKeyTable);
  let binaryText = to_4binary(text);
  // ip置换后的明文
  let ipText = ip_substitution(binaryText);
  let L0 = ipText.substr(0, 32);
  let R0 = ipText.substr(32, 32);
  // 16***变化
  for (let i = 0; i < subKeyCompressTable.length; i++) {
    let K = subKeyCompressTable[i];
    let temp = L0;
    L0 = R0;
    let F = f(R0, K);
    R0 = xor(temp, F);
  }
  // 16轮加密后的结果倒过来
  let R0L0 = R0 + L0;
  let result = ip_inverse_substitution(R0L0);
  return binary_to_hex(result);
}

/**
 * DES解密算法,直接将16个子**的调用位置调转即可
 * */
let des_decrypt = (cipher, key) => {
  if (cipher === null || key === null) {
    return "长度不足64位"
  }
  // 十六进制文本,故64位时长度为16
  if (cipher.length < 16 || key.length < 16) {
    return "长度不足64位"
  }
  let binaryKey = to_4binary(key);
  // 压缩64位**到56位
  let compressedKey = pc_substitution(binaryKey);
  // 生成16个56位子**
  let subKeyTable = sub_key_table(compressedKey);
  // pc2压缩**
  let subKeyCompressTable = sub_key_table_compress(subKeyTable);
  let binaryText = to_4binary(cipher);
  // ip置换后的明文
  let ipText = ip_substitution(binaryText);
  let L0 = ipText.substr(0, 32);
  let R0 = ipText.substr(32, 32);
  // 16***变化
  for (let i = 0; i < subKeyCompressTable.length; i++) {
    let K = subKeyCompressTable[15 - i];
    let temp = L0;
    L0 = R0;
    let F = f(R0, K);
    R0 = xor(temp, F);
  }
  // 16轮加密后的结果倒过来
  let R0L0 = R0 + L0;
  let result = ip_inverse_substitution(R0L0);
  return binary_to_hex(result);
}

export default {
  des_encrypt,
  des_decrypt
}