PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/asmcrypto.js/src/rsa

Просмотр файла: pkcs1.js

import { RSA_reset, RSA_encrypt, RSA_decrypt } from './rsa';
import { Random_getValues } from '../random/random';
import { is_buffer, is_bytes, is_number, is_string, string_to_bytes } from '../utils';
import { IllegalArgumentError, IllegalStateError, SecurityError } from '../errors';

export class RSA_OAEP {
  constructor(options) {
    options = options || {};

    if (!options.hash) throw new SyntaxError("option 'hash' is required");

    if (!options.hash.HASH_SIZE)
      throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function");

    this.hash = options.hash;

    this.label = null;

    this.reset(options);
  }

  reset(options) {
    options = options || {};

    var label = options.label;
    if (label !== undefined) {
      if (is_buffer(label) || is_bytes(label)) {
        label = new Uint8Array(label);
      } else if (is_string(label)) {
        label = string_to_bytes(label);
      } else {
        throw new TypeError('unexpected label type');
      }

      this.label = label.length > 0 ? label : null;
    } else {
      this.label = null;
    }

    RSA_reset.call(this, options);
  }

  /**
   * @param {Uint8Array} data
   * @return {RSA_OAEP}
   */
  encrypt(data) {
    if (!this.key) throw new IllegalStateError('no key is associated with the instance');

    var key_size = Math.ceil(this.key[0].bitLength / 8),
      hash_size = this.hash.HASH_SIZE,
      data_length = data.byteLength || data.length || 0,
      ps_length = key_size - data_length - 2 * hash_size - 2;

    if (data_length > key_size - 2 * this.hash.HASH_SIZE - 2) throw new IllegalArgumentError('data too large');

    var message = new Uint8Array(key_size),
      seed = message.subarray(1, hash_size + 1),
      data_block = message.subarray(hash_size + 1);

    if (is_bytes(data)) {
      data_block.set(data, hash_size + ps_length + 1);
    } else if (is_buffer(data)) {
      data_block.set(new Uint8Array(data), hash_size + ps_length + 1);
    } else if (is_string(data)) {
      data_block.set(string_to_bytes(data), hash_size + ps_length + 1);
    } else {
      throw new TypeError('unexpected data type');
    }

    data_block.set(
      this.hash
        .reset()
        .process(this.label || '')
        .finish().result,
      0,
    );
    data_block[hash_size + ps_length] = 1;

    Random_getValues(seed);

    var data_block_mask = RSA_MGF1_generate.call(this, seed, data_block.length);
    for (var i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i];

    var seed_mask = RSA_MGF1_generate.call(this, data_block, seed.length);
    for (var i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i];

    RSA_encrypt.call(this, message);

    return this;
  }

  /**
   * @param {Uint8Array} data
   * @return {RSA_OAEP}
   */
  decrypt(data) {
    if (!this.key) throw new IllegalStateError('no key is associated with the instance');

    var key_size = Math.ceil(this.key[0].bitLength / 8),
      hash_size = this.hash.HASH_SIZE,
      data_length = data.byteLength || data.length || 0;

    if (data_length !== key_size) throw new IllegalArgumentError('bad data');

    RSA_decrypt.call(this, data);

    var z = this.result[0],
      seed = this.result.subarray(1, hash_size + 1),
      data_block = this.result.subarray(hash_size + 1);

    if (z !== 0) throw new SecurityError('decryption failed');

    var seed_mask = RSA_MGF1_generate.call(this, data_block, seed.length);
    for (var i = 0; i < seed.length; i++) seed[i] ^= seed_mask[i];

    var data_block_mask = RSA_MGF1_generate.call(this, seed, data_block.length);
    for (var i = 0; i < data_block.length; i++) data_block[i] ^= data_block_mask[i];

    var lhash = this.hash
      .reset()
      .process(this.label || '')
      .finish().result;
    for (var i = 0; i < hash_size; i++) {
      if (lhash[i] !== data_block[i]) throw new SecurityError('decryption failed');
    }

    var ps_end = hash_size;
    for (; ps_end < data_block.length; ps_end++) {
      var psz = data_block[ps_end];
      if (psz === 1) break;
      if (psz !== 0) throw new SecurityError('decryption failed');
    }
    if (ps_end === data_block.length) throw new SecurityError('decryption failed');

    this.result = data_block.subarray(ps_end + 1);

    return this;
  }
}

/**
 * @param {Uint8Array} seed
 * @param {number} length
 * @return {Uint8Array}
 * @constructor
 */
function RSA_MGF1_generate(seed, length) {
  seed = seed || '';
  length = length || 0;

  var hash_size = this.hash.HASH_SIZE;
  //    if ( length > (hash_size * 0x100000000) )
  //        throw new IllegalArgumentError("mask length too large");

  var mask = new Uint8Array(length),
    counter = new Uint8Array(4),
    chunks = Math.ceil(length / hash_size);
  for (var i = 0; i < chunks; i++) {
    (counter[0] = i >>> 24), (counter[1] = (i >>> 16) & 255), (counter[2] = (i >>> 8) & 255), (counter[3] = i & 255);

    var submask = mask.subarray(i * hash_size);

    var chunk = this.hash
      .reset()
      .process(seed)
      .process(counter)
      .finish().result;
    if (chunk.length > submask.length) chunk = chunk.subarray(0, submask.length);

    submask.set(chunk);
  }

  return mask;
}

export class RSA_PSS {
  constructor(options) {
    options = options || {};

    if (!options.hash) throw new SyntaxError("option 'hash' is required");

    if (!options.hash.HASH_SIZE)
      throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function");

    this.hash = options.hash;

    this.saltLength = 4;

    this.reset(options);
  }

  reset(options) {
    options = options || {};

    RSA_reset.call(this, options);

    var slen = options.saltLength;
    if (slen !== undefined) {
      if (!is_number(slen) || slen < 0) throw new TypeError('saltLength should be a non-negative number');

      if (this.key !== null && Math.ceil((this.key[0].bitLength - 1) / 8) < this.hash.HASH_SIZE + slen + 2)
        throw new SyntaxError('saltLength is too large');

      this.saltLength = slen;
    } else {
      this.saltLength = 4;
    }
  }

  /**
   * @param {Uint8Array} data
   * @return {RSA_PSS}
   */
  sign(data) {
    if (!this.key) throw new IllegalStateError('no key is associated with the instance');

    var key_bits = this.key[0].bitLength,
      hash_size = this.hash.HASH_SIZE,
      message_length = Math.ceil((key_bits - 1) / 8),
      salt_length = this.saltLength,
      ps_length = message_length - salt_length - hash_size - 2;

    var message = new Uint8Array(message_length),
      h_block = message.subarray(message_length - hash_size - 1, message_length - 1),
      d_block = message.subarray(0, message_length - hash_size - 1),
      d_salt = d_block.subarray(ps_length + 1);

    var m_block = new Uint8Array(8 + hash_size + salt_length),
      m_hash = m_block.subarray(8, 8 + hash_size),
      m_salt = m_block.subarray(8 + hash_size);

    m_hash.set(
      this.hash
        .reset()
        .process(data)
        .finish().result,
    );

    if (salt_length > 0) Random_getValues(m_salt);

    d_block[ps_length] = 1;
    d_salt.set(m_salt);

    h_block.set(
      this.hash
        .reset()
        .process(m_block)
        .finish().result,
    );

    var d_block_mask = RSA_MGF1_generate.call(this, h_block, d_block.length);
    for (var i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i];

    message[message_length - 1] = 0xbc;

    var zbits = 8 * message_length - key_bits + 1;
    if (zbits % 8) message[0] &= 0xff >>> zbits;

    RSA_decrypt.call(this, message);

    return this;
  }

  /**
   * @param {Uint8Array} signature
   * @param {Uint8Array} data
   * @return {RSA_PSS}
   */
  verify(signature, data) {
    if (!this.key) throw new IllegalStateError('no key is associated with the instance');

    var key_bits = this.key[0].bitLength,
      hash_size = this.hash.HASH_SIZE,
      message_length = Math.ceil((key_bits - 1) / 8),
      salt_length = this.saltLength,
      ps_length = message_length - salt_length - hash_size - 2;

    RSA_encrypt.call(this, signature);

    var message = this.result;
    if (message[message_length - 1] !== 0xbc) throw new SecurityError('bad signature');

    var h_block = message.subarray(message_length - hash_size - 1, message_length - 1),
      d_block = message.subarray(0, message_length - hash_size - 1),
      d_salt = d_block.subarray(ps_length + 1);

    var zbits = 8 * message_length - key_bits + 1;
    if (zbits % 8 && message[0] >>> (8 - zbits)) throw new SecurityError('bad signature');

    var d_block_mask = RSA_MGF1_generate.call(this, h_block, d_block.length);
    for (var i = 0; i < d_block.length; i++) d_block[i] ^= d_block_mask[i];

    if (zbits % 8) message[0] &= 0xff >>> zbits;

    for (var i = 0; i < ps_length; i++) {
      if (d_block[i] !== 0) throw new SecurityError('bad signature');
    }
    if (d_block[ps_length] !== 1) throw new SecurityError('bad signature');

    var m_block = new Uint8Array(8 + hash_size + salt_length),
      m_hash = m_block.subarray(8, 8 + hash_size),
      m_salt = m_block.subarray(8 + hash_size);

    m_hash.set(
      this.hash
        .reset()
        .process(data)
        .finish().result,
    );
    m_salt.set(d_salt);

    var h_block_verify = this.hash
      .reset()
      .process(m_block)
      .finish().result;
    for (var i = 0; i < hash_size; i++) {
      if (h_block[i] !== h_block_verify[i]) throw new SecurityError('bad signature');
    }

    return this;
  }
}

export class RSA_PKCS1_v1_5 {
  constructor(options) {
    options = options || {};

    if (!options.hash) throw new SyntaxError("option 'hash' is required");

    if (!options.hash.HASH_SIZE)
      throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function");

    this.hash = options.hash;

    this.reset(options);
  }

  reset(options) {
    options = options || {};

    RSA_reset.call(this, options);
  }

  /**
   * @param {Uint8Array} data
   * @return {RSA_PKCS1_v1_5}
   */
  sign(data) {
    if (!this.key) {
      throw new IllegalStateError('no key is associated with the instance');
    }
    var prefix = getHashPrefix(this.hash);
    var hash_size = this.hash.HASH_SIZE;

    var t_len = prefix.length + hash_size;
    var k = (this.key[0].bitLength + 7) >> 3;
    if (k < t_len + 11) {
      throw new Error('Message too long');
    }

    var m_hash = new Uint8Array(hash_size);
    m_hash.set(
      this.hash
        .reset()
        .process(data)
        .finish().result,
    );

    // EM = 0x00 || 0x01 || PS || 0x00 || T
    var em = new Uint8Array(k);
    var i = 0;
    em[i++] = 0; // 0x00
    em[i++] = 1; // 0x01
    // PS
    for (i; i < k - t_len - 1; i++) {
      em[i] = 0xff;
    }
    em[i++] = 0;
    em.set(prefix, i); // 0x00
    // T
    em.set(m_hash, em.length - hash_size);

    RSA_decrypt.call(this, em);

    return this;
  }

  /**
   * @param {Uint8Array} signature
   * @param {Uint8Array} data
   * @return {RSA_PKCS1_v1_5}
   */
  verify(signature, data) {
    if (!this.key) {
      throw new IllegalStateError('no key is associated with the instance');
    }
    var prefix = getHashPrefix(this.hash);
    var hash_size = this.hash.HASH_SIZE;

    var t_len = prefix.length + hash_size;
    var k = (this.key[0].bitLength + 7) >> 3;
    if (k < t_len + 11) {
      throw new SecurityError('Bad signature');
    }

    RSA_encrypt.call(this, signature);

    var m_hash = new Uint8Array(hash_size);
    m_hash.set(
      this.hash
        .reset()
        .process(data)
        .finish().result,
    );

    var res = 1;
    // EM = 0x00 || 0x01 || PS || 0x00 || T
    var decryptedSignature = this.result;
    var i = 0;
    res &= decryptedSignature[i++] === 0; // 0x00
    res &= decryptedSignature[i++] === 1; // 0x01
    // PS
    for (i; i < k - t_len - 1; i++) {
      res &= decryptedSignature[i] === 0xff;
    }
    res &= decryptedSignature[i++] === 0; // 0x00
    // T
    var j = 0;
    var n = i + prefix.length;
    // prefix
    for (i; i < n; i++) {
      res &= decryptedSignature[i] === prefix[j++];
    }
    j = 0;
    n = i + m_hash.length;
    // hash
    for (i; i < n; i++) {
      res &= decryptedSignature[i] === m_hash[j++];
    }

    if (!res) {
      throw new SecurityError('Bad signature');
    }

    return this;
  }
}

const HASH_PREFIXES = {
  sha1: new Uint8Array([0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14]),
  sha256: new Uint8Array([
    0x30,
    0x31,
    0x30,
    0x0d,
    0x06,
    0x09,
    0x60,
    0x86,
    0x48,
    0x01,
    0x65,
    0x03,
    0x04,
    0x02,
    0x01,
    0x05,
    0x00,
    0x04,
    0x20,
  ]),
  sha384: new Uint8Array([
    0x30,
    0x41,
    0x30,
    0x0d,
    0x06,
    0x09,
    0x60,
    0x86,
    0x48,
    0x01,
    0x65,
    0x03,
    0x04,
    0x02,
    0x02,
    0x05,
    0x00,
    0x04,
    0x30,
  ]),
  sha512: new Uint8Array([
    0x30,
    0x51,
    0x30,
    0x0d,
    0x06,
    0x09,
    0x60,
    0x86,
    0x48,
    0x01,
    0x65,
    0x03,
    0x04,
    0x02,
    0x03,
    0x05,
    0x00,
    0x04,
    0x40,
  ]),
};

/**
 * @param hash
 * @return {Uint8Array}
 */
function getHashPrefix(hash) {
  var hashName = hash.constructor.NAME;
  var prefix = HASH_PREFIXES[hashName];
  if (!prefix) {
    throw new Error("Cannot get hash prefix for hash algorithm '" + hashName + "'");
  }
  return prefix;
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!