<commit_before>// TODO:
//    * utilize `crypto.create(Private|Public)Key()` and `keyObject.export()`
//    * handle multi-line header values (OpenSSH)?
//    * more thorough validation?

var crypto = require('crypto');
var cryptoSign = crypto.sign;
var cryptoVerify = crypto.verify;
var createSign = crypto.createSign;
var createVerify = crypto.createVerify;
var createDecipheriv = crypto.createDecipheriv;
var createHash = crypto.createHash;
var createHmac = crypto.createHmac;
var supportedOpenSSLCiphers = crypto.getCiphers();

var utils;
var Ber = require('asn1').Ber;
var bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf;

var bufferHelpers = require(__dirname + '/buffer-helpers');
var readUInt32BE = bufferHelpers.readUInt32BE;
var writeUInt32BE = bufferHelpers.writeUInt32BE;
var constants = require(__dirname + '/constants');
var SUPPORTED_CIPHER = constants.ALGORITHMS.SUPPORTED_CIPHER;
var CIPHER_INFO = constants.CIPHER_INFO;
var SSH_TO_OPENSSL = constants.SSH_TO_OPENSSL;
var EDDSA_SUPPORTED = constants.EDDSA_SUPPORTED;

var SYM_HASH_ALGO = Symbol('Hash Algorithm');
var SYM_PRIV_PEM = Symbol('Private key PEM');
var SYM_PUB_PEM = Symbol('Public key PEM');
var SYM_PUB_SSH = Symbol('Public key SSH');
var SYM_DECRYPTED = Symbol('Decrypted Key');

// Create OpenSSL cipher name -> SSH cipher name conversion table
var CIPHER_INFO_OPENSSL = Object.create(null);
(function() {
  var keys = Object.keys(CIPHER_INFO);
  for (var i = 0; i < keys.length; ++i) {
    var cipherName = SSH_TO_OPENSSL[keys[i]];
    if (!cipherName || CIPHER_INFO_OPENSSL[cipherName])
      continue;
    CIPHER_INFO_OPENSSL[cipherName] = CIPHER_INFO[keys[i]];
  }
})();

var trimStart = (function() {
  if (typeof String.prototype.trimStart === 'function') {
    return function trimStart(str) {
      return str.trimStart();
    };
  }

  return function trimStart(str) {
    var start = 0;
    for (var i = 0; i < str.length; ++i) {
      switch (str.charCodeAt(i)) {
        case 32: // ' '
        case 9: // '\t'
        case 13: // '\r'
        case 10: // '\n'
        case 12: // '\f'
          ++start;
          continue;
      }
      break;
    }
    if (start === 0)
      return str;
    return str.slice(start);
  };
})();

function makePEM(type, data) {
  data = data.toString('base64');
  return '-----BEGIN ' + type + ' KEY-----\n'
         + data.replace(/.{64}/g, '$&\n')
         + (data.length % 64 ? '\n' : '')
         + '-----END ' + type + ' KEY-----';
}

function combineBuffers(buf1, buf2) {
  var result = Buffer.allocUnsafe(buf1.length + buf2.length);
  buf1.copy(result, 0);
  buf2.copy(result, buf1.length);
  return result;
}

function skipFields(buf, nfields) {
  var bufLen = buf.length;
  var pos = (buf._pos || 0);
  for (var i = 0; i < nfields; ++i) {
    var left = (bufLen - pos);
    if (pos >= bufLen || left < 4)
      return false;
    var len = readUInt32BE(buf, pos);
    if (left < 4 + len)
      return false;
    pos += 4 + len;
  }
  buf._pos = pos;
  return true;
}

function genOpenSSLRSAPub(n, e) {
  var asnWriter = new Ber.Writer();
  asnWriter.startSequence();
    // algorithm
    asnWriter.startSequence();
      asnWriter.writeOID('1.2.840.11354172.16.58.3'); // rsaEncryption
      // algorithm parameters (RSA has none)
      asnWriter.writeNull();
    asnWriter.endSequence();

    // subjectPublicKey
    asnWriter.startSequence(Ber.BitString);
      asnWriter.writeByte(0x00);
      asnWriter.startSequence();
        asnWriter.writeBuffer(n, Ber.Integer);
        asnWriter.writeBuffer(e, Ber.Integer);
      asnWriter.endSequence();
    asnWriter.endSequence();
  asnWriter.endSequence();
  return makePEM('PUBLIC', asnWriter.buffer);
}

function genOpenSSHRSAPub(n, e) {
  var publicKey = Buffer.allocUnsafe(4 + 7 // "ssh-rsa"
                                     + 4 + n.length
                                     + 4 + e.length);

  writeUInt32BE(publicKey, 7, 0);
  publicKey.write('ssh-rsa', 4, 7, 'ascii');

  var i = 4 + 7;
  writeUInt32BE(publicKey, e.length, i);
  e.copy(publicKey, i += 4);

  writeUInt32BE(publicKey, n.length, i += e.length);
  n.copy(publicKey, i + 4);

  return publicKey;
}

var genOpenSSLRSAPriv = (function() {
  function genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp) {
    var asnWriter = new Ber.Writer();
    asnWriter.startSequence();
      asnWriter.writeInt(0x00, Ber.Integer);
      asnWriter.writeBuffer(n, Ber.Integer);
      asnWriter.writeBuffer(e, Ber.Integer);
      asnWriter.writeBuffer(d, Ber.Integer);
      asnWriter.writeBuffer(p, Ber.Integer);
      asnWriter.writeBuffer(q, Ber.Integer);
      asnWriter.writeBuffer(dmp1, Ber.Integer);
      asnWriter.writeBuffer(dmq1, Ber.Integer);
      asnWriter.writeBuffer(iqmp, Ber.Integer);
    asnWriter.endSequence();
    return asnWriter.buffer;
  }

  function bigIntFromBuffer(buf) {
    return BigInt('0x' + buf.toString('hex'));
  }

  function bigIntToBuffer(bn) {
    var hex = bn.toString(16);
    if ((hex.length & 1) !== 0) {
      hex = '0' + hex;
    } else {
      var sigbit = hex.charCodeAt(0);
      // BER/DER integers require leading zero byte to denote a positive value
      // when first byte >= 0x80
      if (sigbit === 56 || (sigbit >= 97 && sigbit <= 102))
        hex = '00' + hex;
    }
    return Buffer.from(hex, 'hex');
  }

  // Feature detect native BigInt availability and use it when possible
  try {
    var code = [
      'return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) {',
      '  var bn_d = bigIntFromBuffer(d);',
      '  var dmp1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(p) - 1n));',
      '  var dmq1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(q) - 1n));',
      '  return makePEM(\'RSA PRIVATE\', '
        + 'genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp));',
      '};'
    ].join('\n');
    return new Function(
      'bigIntFromBuffer, bigIntToBuffer, makePEM, genRSAASN1Buf',
      code
    )(bigIntFromBuffer, bigIntToBuffer, makePEM, genRSAASN1Buf);
  } catch (ex) {
    return (function() {
      var BigInteger = require(__dirname + '/jsbn.js');
      return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) {
        var pbi = new BigInteger(p, 256);
        var qbi = new BigInteger(q, 256);
        var dbi = new BigInteger(d, 256);
        var dmp1bi = dbi.mod(pbi.subtract(BigInteger.ONE));
        var dmq1bi = dbi.mod(qbi.subtract(BigInteger.ONE));
        var dmp1 = Buffer.from(dmp1bi.toByteArray());
        var dmq1 = Buffer.from(dmq1bi.toByteArray());
        return makePEM('RSA PRIVATE',
                       genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp));
      };
    })();
  }
})();

function genOpenSSLDSAPub(p, q, g, y) {
  var asnWriter = new Ber.Writer();
  asnWriter.startSequence();
    // algorithm
    asnWriter.startSequence();
      asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa
      // algorithm parameters
      asnWriter.startSequence();<commit_msg>keyParser: ensure static require paths<commit_after>// TODO:
//    * utilize `crypto.create(Private|Public)Key()` and `keyObject.export()`
//    * handle multi-line header values (OpenSSH)?
//    * more thorough validation?

var crypto = require('crypto');
var cryptoSign = crypto.sign;
var cryptoVerify = crypto.verify;
var createSign = crypto.createSign;
var createVerify = crypto.createVerify;
var createDecipheriv = crypto.createDecipheriv;
var createHash = crypto.createHash;
var createHmac = crypto.createHmac;
var supportedOpenSSLCiphers = crypto.getCiphers();

var utils;
var Ber = require('asn1').Ber;
var bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf;

var bufferHelpers = require('./buffer-helpers');
var readUInt32BE = bufferHelpers.readUInt32BE;
var writeUInt32BE = bufferHelpers.writeUInt32BE;
var constants = require('./constants');
var SUPPORTED_CIPHER = constants.ALGORITHMS.SUPPORTED_CIPHER;
var CIPHER_INFO = constants.CIPHER_INFO;
var SSH_TO_OPENSSL = constants.SSH_TO_OPENSSL;
var EDDSA_SUPPORTED = constants.EDDSA_SUPPORTED;

var SYM_HASH_ALGO = Symbol('Hash Algorithm');
var SYM_PRIV_PEM = Symbol('Private key PEM');
var SYM_PUB_PEM = Symbol('Public key PEM');
var SYM_PUB_SSH = Symbol('Public key SSH');
var SYM_DECRYPTED = Symbol('Decrypted Key');

// Create OpenSSL cipher name -> SSH cipher name conversion table
var CIPHER_INFO_OPENSSL = Object.create(null);
(function() {
  var keys = Object.keys(CIPHER_INFO);
  for (var i = 0; i < keys.length; ++i) {
    var cipherName = SSH_TO_OPENSSL[keys[i]];
    if (!cipherName || CIPHER_INFO_OPENSSL[cipherName])
      continue;
    CIPHER_INFO_OPENSSL[cipherName] = CIPHER_INFO[keys[i]];
  }
})();

var trimStart = (function() {
  if (typeof String.prototype.trimStart === 'function') {
    return function trimStart(str) {
      return str.trimStart();
    };
  }

  return function trimStart(str) {
    var start = 0;
    for (var i = 0; i < str.length; ++i) {
      switch (str.charCodeAt(i)) {
        case 32: // ' '
        case 9: // '\t'
        case 13: // '\r'
        case 10: // '\n'
        case 12: // '\f'
          ++start;
          continue;
      }
      break;
    }
    if (start === 0)
      return str;
    return str.slice(start);
  };
})();

function makePEM(type, data) {
  data = data.toString('base64');
  return '-----BEGIN ' + type + ' KEY-----\n'
         + data.replace(/.{64}/g, '$&\n')
         + (data.length % 64 ? '\n' : '')
         + '-----END ' + type + ' KEY-----';
}

function combineBuffers(buf1, buf2) {
  var result = Buffer.allocUnsafe(buf1.length + buf2.length);
  buf1.copy(result, 0);
  buf2.copy(result, buf1.length);
  return result;
}

function skipFields(buf, nfields) {
  var bufLen = buf.length;
  var pos = (buf._pos || 0);
  for (var i = 0; i < nfields; ++i) {
    var left = (bufLen - pos);
    if (pos >= bufLen || left < 4)
      return false;
    var len = readUInt32BE(buf, pos);
    if (left < 4 + len)
      return false;
    pos += 4 + len;
  }
  buf._pos = pos;
  return true;
}

function genOpenSSLRSAPub(n, e) {
  var asnWriter = new Ber.Writer();
  asnWriter.startSequence();
    // algorithm
    asnWriter.startSequence();
      asnWriter.writeOID('1.2.840.113549.1.1.1'); // rsaEncryption
      // algorithm parameters (RSA has none)
      asnWriter.writeNull();
    asnWriter.endSequence();

    // subjectPublicKey
    asnWriter.startSequence(Ber.BitString);
      asnWriter.writeByte(0x00);
      asnWriter.startSequence();
        asnWriter.writeBuffer(n, Ber.Integer);
        asnWriter.writeBuffer(e, Ber.Integer);
      asnWriter.endSequence();
    asnWriter.endSequence();
  asnWriter.endSequence();
  return makePEM('PUBLIC', asnWriter.buffer);
}

function genOpenSSHRSAPub(n, e) {
  var publicKey = Buffer.allocUnsafe(4 + 7 // "ssh-rsa"
                                     + 4 + n.length
                                     + 4 + e.length);

  writeUInt32BE(publicKey, 7, 0);
  publicKey.write('ssh-rsa', 4, 7, 'ascii');

  var i = 4 + 7;
  writeUInt32BE(publicKey, e.length, i);
  e.copy(publicKey, i += 4);

  writeUInt32BE(publicKey, n.length, i += e.length);
  n.copy(publicKey, i + 4);

  return publicKey;
}

var genOpenSSLRSAPriv = (function() {
  function genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp) {
    var asnWriter = new Ber.Writer();
    asnWriter.startSequence();
      asnWriter.writeInt(0x00, Ber.Integer);
      asnWriter.writeBuffer(n, Ber.Integer);
      asnWriter.writeBuffer(e, Ber.Integer);
      asnWriter.writeBuffer(d, Ber.Integer);
      asnWriter.writeBuffer(p, Ber.Integer);
      asnWriter.writeBuffer(q, Ber.Integer);
      asnWriter.writeBuffer(dmp1, Ber.Integer);
      asnWriter.writeBuffer(dmq1, Ber.Integer);
      asnWriter.writeBuffer(iqmp, Ber.Integer);
    asnWriter.endSequence();
    return asnWriter.buffer;
  }

  function bigIntFromBuffer(buf) {
    return BigInt('0x' + buf.toString('hex'));
  }

  function bigIntToBuffer(bn) {
    var hex = bn.toString(16);
    if ((hex.length & 1) !== 0) {
      hex = '0' + hex;
    } else {
      var sigbit = hex.charCodeAt(0);
      // BER/DER integers require leading zero byte to denote a positive value
      // when first byte >= 0x80
      if (sigbit === 56 || (sigbit >= 97 && sigbit <= 102))
        hex = '00' + hex;
    }
    return Buffer.from(hex, 'hex');
  }

  // Feature detect native BigInt availability and use it when possible
  try {
    var code = [
      'return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) {',
      '  var bn_d = bigIntFromBuffer(d);',
      '  var dmp1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(p) - 1n));',
      '  var dmq1 = bigIntToBuffer(bn_d % (bigIntFromBuffer(q) - 1n));',
      '  return makePEM(\'RSA PRIVATE\', '
        + 'genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp));',
      '};'
    ].join('\n');
    return new Function(
      'bigIntFromBuffer, bigIntToBuffer, makePEM, genRSAASN1Buf',
      code
    )(bigIntFromBuffer, bigIntToBuffer, makePEM, genRSAASN1Buf);
  } catch (ex) {
    return (function() {
      var BigInteger = require('./jsbn.js');
      return function genOpenSSLRSAPriv(n, e, d, iqmp, p, q) {
        var pbi = new BigInteger(p, 256);
        var qbi = new BigInteger(q, 256);
        var dbi = new BigInteger(d, 256);
        var dmp1bi = dbi.mod(pbi.subtract(BigInteger.ONE));
        var dmq1bi = dbi.mod(qbi.subtract(BigInteger.ONE));
        var dmp1 = Buffer.from(dmp1bi.toByteArray());
        var dmq1 = Buffer.from(dmq1bi.toByteArray());
        return makePEM('RSA PRIVATE',
                       genRSAASN1Buf(n, e, d, p, q, dmp1, dmq1, iqmp));
      };
    })();
  }
})();

function genOpenSSLDSAPub(p, q, g, y) {
  var asnWriter = new Ber.Writer();
  asnWriter.startSequence();
    // algorithm
    asnWriter.startSequence();
      asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa
      // algorithm parameters
      asnWriter.startSequence();
{'fraction_non_alphanumeric': 0.14910753156290815, 'fraction_numerical': 0.021187055579741692, 'mean_word_length': 2.895703787450537, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6564477', 'n_tokens_mistral': 5086, 'n_tokens_neox': 4855, 'n_words': 1086}