function SFTPStream(cfg, remoteIdentRaw) { if (typeof cfg === 'string' && !remoteIdentRaw) { remoteIdentRaw = cfg; cfg = undefined; } if (typeof cfg !== 'object' || !cfg) cfg = {}; TransformStream.call(this, { highWaterMark: (typeof cfg.highWaterMark === 'number' ? cfg.highWaterMark : 32 * 1024) }); this.debug = (typeof cfg.debug === 'function' ? cfg.debug : DEBUG_NOOP); this.server = (cfg.server ? true : false); this._isOpenSSH = (remoteIdentRaw && RE_OPENSSH.test(remoteIdentRaw)); this._needContinue = false; this._state = { // common status: 'packet_header', writeReqid: -1, pktLeft: undefined, pktHdrBuf: new Buffer(9), // room for pktLen + pktType + req id pktBuf: undefined, pktType: undefined, version: undefined, extensions: {}, // client maxDataLen: (this._isOpenSSH ? OPENSSH_MAX_DATA_LEN : 32768), requests: {} }; var self = this; this.on('end', function() { self.readable = false; }).on('finish', onFinish) .on('prefinish', onFinish); function onFinish() { self.writable = false; self._cleanup(false); } if (!this.server) this.push(CLIENT_VERSION_BUFFER); }
n/a
function Stats(initial) { this.mode = (initial && initial.mode); this.permissions = this.mode; // backwards compatiblity this.uid = (initial && initial.uid); this.gid = (initial && initial.gid); this.size = (initial && initial.size); this.atime = (initial && initial.atime); this.mtime = (initial && initial.mtime); }
n/a
function SSH2Stream(cfg) { if (typeof cfg !== 'object' || cfg === null) cfg = {}; TransformStream.call(this, { highWaterMark: (typeof cfg.highWaterMark === 'number' ? cfg.highWaterMark : 32 * 1024) }); this._needContinue = false; this.bytesSent = this.bytesReceived = 0; this.debug = (typeof cfg.debug === 'function' ? cfg.debug : DEBUG_NOOP); this.server = (cfg.server === true); this.maxPacketSize = (typeof cfg.maxPacketSize === 'number' ? cfg.maxPacketSize : MAX_PACKET_SIZE); // Bitmap that indicates any bugs the remote side has. This is determined // by the reported software version. this.remoteBugs = 0; if (this.server) { // TODO: Remove when we support group exchange for server implementation this.remoteBugs = BUGS.BAD_DHGEX; } var self = this; var hostKeys = cfg.hostKeys; if (this.server && (typeof hostKeys !== 'object' || hostKeys === null)) throw new Error('hostKeys must be an object keyed on host key type'); this.config = { // Server hostKeys: hostKeys, // All keys supported by server // Client/Server ident: 'SSH-2.0-' + (cfg.ident || ('ssh2js' + MODULE_VER + (this.server ? 'srv' : ''))), algorithms: { kex: ALGORITHMS.KEX, kexBuf: ALGORITHMS.KEX_BUF, serverHostKey: ALGORITHMS.SERVER_HOST_KEY, serverHostKeyBuf: ALGORITHMS.SERVER_HOST_KEY_BUF, cipher: ALGORITHMS.CIPHER, cipherBuf: ALGORITHMS.CIPHER_BUF, hmac: ALGORITHMS.HMAC, hmacBuf: ALGORITHMS.HMAC_BUF, compress: ALGORITHMS.COMPRESS, compressBuf: ALGORITHMS.COMPRESS_BUF } }; // RFC 4253 states the identification string must not contain NULL this.config.ident.replace(RE_NULL, ''); if (this.config.ident.length + 2 /* Account for "\r\n" */ > 255) throw new Error('ident too long'); if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algos = cfg.algorithms; if (Array.isArray(algos.kex) && algos.kex.length > 0) { this.config.algorithms.kex = algos.kex; if (!Buffer.isBuffer(algos.kexBuf)) algos.kexBuf = new Buffer(algos.kex.join(','), 'ascii'); this.config.algorithms.kexBuf = algos.kexBuf; } if (Array.isArray(algos.serverHostKey) && algos.serverHostKey.length > 0) { this.config.algorithms.serverHostKey = algos.serverHostKey; if (!Buffer.isBuffer(algos.serverHostKeyBuf)) { algos.serverHostKeyBuf = new Buffer(algos.serverHostKey.join(','), 'ascii'); } this.config.algorithms.serverHostKeyBuf = algos.serverHostKeyBuf; } if (Array.isArray(algos.cipher) && algos.cipher.length > 0) { this.config.algorithms.cipher = algos.cipher; if (!Buffer.isBuffer(algos.cipherBuf)) algos.cipherBuf = new Buffer(algos.cipher.join(','), 'ascii'); this.config.algorithms.cipherBuf = algos.cipherBuf; } if (Array.isArray(algos.hmac) && algos.hmac.length > 0) { this.config.algorithms.hmac = algos.hmac; if (!Buffer.isBuffer(algos.hmacBuf)) algos.hmacBuf = new Buffer(algos.hmac.join(','), 'ascii'); this.config.algorithms.hmacBuf = algos.hmacBuf; } if (Array.isArray(algos.compress) && algos.compress.length > 0) { this.config.algorithms.compress = algos.compress; if (!Buffer.isBuffer(algos.compressBuf)) algos.compressBuf = new Buffer(algos.compress.join(','), 'ascii'); this.config.algorithms.compressBuf = algos.compressBuf; } } this.reset(true); // Common events this.on('end', function() { // Let GC collect any Buffers we were previously storing self._state = undefined; self.reset(); self._state.incoming.hmac.bufCompute = undefined; self._state.outgoing.bufSeqno = undefined; }); this.on('DISCONNECT', function(reason, code, desc, lang) { onDISCONNECT(self, reason, code, desc, lang); }); this.on('KEXINIT', function(init, firstFollows) { onKEXINIT(self, ...
n/a
function BigInteger(a, b, c) { if(a != null) if("number" == typeof a) this.fromNumber(a,b,c); else if(b == null && "string" != typeof a) this.fromString(a,256); else this.fromString(a,b); }
n/a
function SFTPStream(cfg, remoteIdentRaw) { if (typeof cfg === 'string' && !remoteIdentRaw) { remoteIdentRaw = cfg; cfg = undefined; } if (typeof cfg !== 'object' || !cfg) cfg = {}; TransformStream.call(this, { highWaterMark: (typeof cfg.highWaterMark === 'number' ? cfg.highWaterMark : 32 * 1024) }); this.debug = (typeof cfg.debug === 'function' ? cfg.debug : DEBUG_NOOP); this.server = (cfg.server ? true : false); this._isOpenSSH = (remoteIdentRaw && RE_OPENSSH.test(remoteIdentRaw)); this._needContinue = false; this._state = { // common status: 'packet_header', writeReqid: -1, pktLeft: undefined, pktHdrBuf: new Buffer(9), // room for pktLen + pktType + req id pktBuf: undefined, pktType: undefined, version: undefined, extensions: {}, // client maxDataLen: (this._isOpenSSH ? OPENSSH_MAX_DATA_LEN : 32768), requests: {} }; var self = this; this.on('end', function() { self.readable = false; }).on('finish', onFinish) .on('prefinish', onFinish); function onFinish() { self.writable = false; self._cleanup(false); } if (!this.server) this.push(CLIENT_VERSION_BUFFER); }
n/a
function Stats(initial) { this.mode = (initial && initial.mode); this.permissions = this.mode; // backwards compatiblity this.uid = (initial && initial.uid); this.gid = (initial && initial.gid); this.size = (initial && initial.size); this.atime = (initial && initial.atime); this.mtime = (initial && initial.mtime); }
n/a
function flagsToString(flags) { for (var i = 0; i < stringFlagMapKeys.length; ++i) { var key = stringFlagMapKeys[i]; if (stringFlagMap[key] === flags) return key; } return null; }
n/a
function stringToFlags(str) { var flags = stringFlagMap[str]; if (flags !== undefined) return flags; return null; }
n/a
function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(this); var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; if (options) { if (typeof options.transform === 'function') this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { done(stream, er); }); else done(stream); }); }
n/a
function Stats(initial) { this.mode = (initial && initial.mode); this.permissions = this.mode; // backwards compatiblity this.uid = (initial && initial.uid); this.gid = (initial && initial.gid); this.size = (initial && initial.size); this.atime = (initial && initial.atime); this.mtime = (initial && initial.mtime); }
n/a
_checkModeProperty = function (property) { return ((this.mode & constants.S_IFMT) === property); }
n/a
isBlockDevice = function () { return this._checkModeProperty(constants.S_IFBLK); }
n/a
isCharacterDevice = function () { return this._checkModeProperty(constants.S_IFCHR); }
n/a
isDirectory = function () { return this._checkModeProperty(constants.S_IFDIR); }
n/a
isFIFO = function () { return this._checkModeProperty(constants.S_IFIFO); }
n/a
isFile = function () { return this._checkModeProperty(constants.S_IFREG); }
n/a
isSocket = function () { return this._checkModeProperty(constants.S_IFSOCK); }
n/a
isSymbolicLink = function () { return this._checkModeProperty(constants.S_IFLNK); }
n/a
__push = function (chunk, encoding) { this._transformState.needTransform = false; return Duplex.prototype.push.call(this, chunk, encoding); }
n/a
__read = function (n) { var ts = this._transformState; if (ts.writechunk !== null && ts.writecb && !ts.transforming) { ts.transforming = true; this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else { // mark that we need a transform, so that any data that comes in // will get processed, now that we've asked for it. ts.needTransform = true; } }
n/a
_cleanup = function (callback) { var state = this._state; state.pktBuf = undefined; // give GC something to do var requests = state.requests; var keys = Object.keys(requests); var len = keys.length; if (len) { if (this.readable) { var err = new Error('SFTP session ended early'); for (var i = 0, cb; i < len; ++i) (cb = requests[keys[i]].cb) && cb(err); } state.requests = {}; } if (this.readable) this.push(null); else if (!this._readableState.endEmitted && !this._readableState.flowing) { // Ugh! this.resume(); } if (callback !== false) { this.debug('DEBUG[SFTP]: Parser: Malformed packet'); callback && callback(new Error('Malformed packet')); } }
n/a
_read = function (n) { if (this._needContinue) { this._needContinue = false; this.emit('continue'); } return this.__read(n); }
n/a
_transform = function (chunk, encoding, callback) {
var state = this._state;
var server = this.server;
var status = state.status;
var pktType = state.pktType;
var pktBuf = state.pktBuf;
var pktLeft = state.pktLeft;
var version = state.version;
var pktHdrBuf = state.pktHdrBuf;
var requests = state.requests;
var debug = this.debug;
var chunkLen = chunk.length;
var chunkPos = 0;
var buffer;
var chunkLeft;
var id;
while (true) {
if (status === 'discard') {
chunkLeft = (chunkLen - chunkPos);
if (pktLeft <= chunkLeft) {
chunkPos += pktLeft;
pktLeft = 0;
status = 'packet_header';
buffer = pktBuf = undefined;
} else {
pktLeft -= chunkLeft;
break;
}
} else if (pktBuf !== undefined) {
chunkLeft = (chunkLen - chunkPos);
if (pktLeft <= chunkLeft) {
chunk.copy(pktBuf,
pktBuf.length - pktLeft,
chunkPos,
chunkPos + pktLeft);
chunkPos += pktLeft;
pktLeft = 0;
buffer = pktBuf;
pktBuf = undefined;
continue;
} else {
chunk.copy(pktBuf, pktBuf.length - pktLeft, chunkPos);
pktLeft -= chunkLeft;
break;
}
} else if (status === 'packet_header') {
if (!buffer) {
pktLeft = 5;
pktBuf = pktHdrBuf;
} else {
// here we read the right-most 5 bytes from buffer (pktHdrBuf)
pktLeft = buffer.readUInt32BE(4, true) - 1; // account for type byte
pktType = buffer[8];
if (server) {
if (version === undefined && pktType !== REQUEST.INIT) {
debug('DEBUG[SFTP]: Parser: Unexpected packet before init');
status = 'bad_pkt';
} else if (version !== undefined && pktType === REQUEST.INIT) {
debug('DEBUG[SFTP]: Parser: Unexpected duplicate init');
status = 'bad_pkt';
} else if (pktLeft > MAX_PKT_LEN) {
debug('DEBUG[SFTP]: Parser: Packet length ('
+ pktLeft
+ ') exceeds max length ('
+ MAX_PKT_LEN
+ ')');
status = 'bad_pkt';
} else if (pktType === REQUEST.EXTENDED)
status = 'bad_pkt';
else if (REQUEST[pktType] === undefined) {
debug('DEBUG[SFTP]: Parser: Unsupported packet type: ' + pktType);
status = 'discard';
}
} else if (version === undefined && pktType !== RESPONSE.VERSION) {
debug('DEBUG[SFTP]: Parser: Unexpected packet before version');
status = 'bad_pkt';
} else if (version !== undefined && pktType === RESPONSE.VERSION) {
debug('DEBUG[SFTP]: Parser: Unexpected duplicate version');
status = 'bad_pkt';
} else if (RESPONSE[pktType] === undefined)
status = 'discard';
if (status === 'bad_pkt') {
// copy original packet info
pktHdrBuf.writeUInt32BE(pktLeft, 0, true);
pktHdrBuf[4] = pktType;
pktLeft = 4;
pktBuf = pktHdrBuf;
} else {
pktBuf = new Buffer(pktLeft);
status = 'payload';
}
}
} else if (status === 'payload') {
if (pktType === RESPONSE.VERSION || pktType === REQUEST.INIT) {
/*
uint32 version
<extension data>
*/
version = state.version = readInt(buffer, 0, this, callback);
if (version === false)
return;
if (version < 3) {
this._cleanup();
return callback(new Error('Incompatible SFTP version: ' + version));
} else if (server)
this.push(SERVER_VERSION_BUFFER);
var buflen = buffer.length;
var extname;
var extdata;
buffer._pos = 4;
while (buffer._pos < buflen) {
extname = readString(buffer, buffer._pos, 'ascii', this, callback);
if (extname === false)
return;
extdata = readString(buffer, buffer._pos, 'ascii', this, callback);
if (extdata === ...
n/a
appendFile = function (path, data, options, callback_) { if (this.server) throw new Error('Client-only method called in server mode'); var callback; if (typeof callback_ === 'function') { callback = callback_; } else if (typeof options === 'function') { callback = options; options = undefined; } if (typeof options === 'string') options = { encoding: options, mode: 438, flag: 'a' }; else if (!options) options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' }; else if (typeof options !== 'object') throw new TypeError('Bad arguments'); if (!options.flag) options = util._extend({ flag: 'a' }, options); this.writeFile(path, data, options, callback); }
n/a
attrs = function (id, attrs) { if (!this.server) throw new Error('Server-only method called in client mode'); if (typeof attrs !== 'object') throw new Error('attrs is not an object'); var info = attrsToBytes(attrs); var buf = new Buffer(4 + 1 + 4 + 4 + info.nbytes); var p = 13; buf.writeUInt32BE(buf.length - 4, 0, true); buf[4] = RESPONSE.ATTRS; buf.writeUInt32BE(id, 5, true); buf.writeUInt32BE(info.flags, 9, true); if (info.flags && info.bytes) { var bytes = info.bytes; for (var j = 0, len = bytes.length; j < len; ++j) for (var k = 0, len2 = bytes[j].length; k < len2; ++k) buf[p++] = bytes[j][k]; } this.debug('DEBUG[SFTP]: Outgoing: Writing ATTRS'); return this.push(buf); }
n/a
chmod = function (path, mode, cb) { return this.setstat(path, { mode: mode }, cb); }
n/a
chown = function (path, uid, gid, cb) { return this.setstat(path, { uid: uid, gid: gid }, cb); }
n/a
close = function (handle, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
var state = this._state;
/*
uint32 id
string handle
*/
var handlelen = handle.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + handlelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.CLOSE;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(handlelen, p, true);
handle.copy(buf, p += 4);
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing CLOSE');
return this.push(buf);
}
n/a
createReadStream = function (path, options) { if (this.server) throw new Error('Client-only method called in server mode'); return new ReadStream(this, path, options); }
n/a
createWriteStream = function (path, options) { if (this.server) throw new Error('Client-only method called in server mode'); return new WriteStream(this, path, options); }
n/a
data = function (id, data, encoding) { if (!this.server) throw new Error('Server-only method called in client mode'); var isBuffer = Buffer.isBuffer(data); if (!isBuffer && typeof data !== 'string') throw new Error('data is not a Buffer or string'); if (!isBuffer) encoding || (encoding = 'utf8'); var dataLen = (isBuffer ? data.length : Buffer.byteLength(data, encoding)); var buf = new Buffer(4 + 1 + 4 + 4 + dataLen); buf.writeUInt32BE(buf.length - 4, 0, true); buf[4] = RESPONSE.DATA; buf.writeUInt32BE(id, 5, true); buf.writeUInt32BE(dataLen, 9, true); if (dataLen) { if (isBuffer) data.copy(buf, 13); else buf.write(data, 13, dataLen, encoding); } this.debug('DEBUG[SFTP]: Outgoing: Writing DATA'); return this.push(buf); }
n/a
exists = function (path, cb) { if (this.server) throw new Error('Client-only method called in server mode'); this.stat(path, function(err) { cb && cb(err ? false : true); }); }
n/a
ext_openssh_fstatvfs = function (handle, cb) {
var state = this._state;
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!state.extensions['fstatvfs@openssh.com']
|| state.extensions['fstatvfs@openssh.com'].indexOf('2') === -1)
throw new Error('Server does not support this extended request');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
/*
uint32 id
string "fstatvfs@openssh.com"
string handle
*/
var handlelen = handle.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + 20 + 4 + handlelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.EXTENDED;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(20, p, true);
buf.write('fstatvfs@openssh.com', p += 4, 20, 'ascii');
buf.writeUInt32BE(handlelen, p += 20, true);
buf.write(handle, p += 4, handlelen, 'utf8');
state.requests[reqid] = {
extended: 'fstatvfs@openssh.com',
cb: cb
};
this.debug('DEBUG[SFTP]: Outgoing: Writing fstatvfs@openssh.com');
return this.push(buf);
}
n/a
ext_openssh_fsync = function (handle, cb) {
var state = this._state;
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!state.extensions['fsync@openssh.com']
|| state.extensions['fsync@openssh.com'].indexOf('1') === -1)
throw new Error('Server does not support this extended request');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
/*
uint32 id
string "fsync@openssh.com"
string handle
*/
var handlelen = handle.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + 17 + 4 + handlelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.EXTENDED;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(17, p, true);
buf.write('fsync@openssh.com', p += 4, 17, 'ascii');
buf.writeUInt32BE(handlelen, p += 17, true);
buf.write(handle, p += 4, handlelen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing fsync@openssh.com');
return this.push(buf);
}
n/a
ext_openssh_hardlink = function (oldPath, newPath, cb) {
var state = this._state;
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!state.extensions['hardlink@openssh.com']
|| state.extensions['hardlink@openssh.com'].indexOf('1') === -1)
throw new Error('Server does not support this extended request');
/*
uint32 id
string "hardlink@openssh.com"
string oldpath
string newpath
*/
var oldlen = Buffer.byteLength(oldPath);
var newlen = Buffer.byteLength(newPath);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + 20 + 4 + oldlen + 4 + newlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.EXTENDED;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(20, p, true);
buf.write('hardlink@openssh.com', p += 4, 20, 'ascii');
buf.writeUInt32BE(oldlen, p += 20, true);
buf.write(oldPath, p += 4, oldlen, 'utf8');
buf.writeUInt32BE(newlen, p += oldlen, true);
buf.write(newPath, p += 4, newlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing hardlink@openssh.com');
return this.push(buf);
}
n/a
ext_openssh_rename = function (oldPath, newPath, cb) {
var state = this._state;
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!state.extensions['posix-rename@openssh.com']
|| state.extensions['posix-rename@openssh.com'].indexOf('1') === -1)
throw new Error('Server does not support this extended request');
/*
uint32 id
string "posix-rename@openssh.com"
string oldpath
string newpath
*/
var oldlen = Buffer.byteLength(oldPath);
var newlen = Buffer.byteLength(newPath);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + 24 + 4 + oldlen + 4 + newlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.EXTENDED;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(24, p, true);
buf.write('posix-rename@openssh.com', p += 4, 24, 'ascii');
buf.writeUInt32BE(oldlen, p += 24, true);
buf.write(oldPath, p += 4, oldlen, 'utf8');
buf.writeUInt32BE(newlen, p += oldlen, true);
buf.write(newPath, p += 4, newlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing posix-rename@openssh.com');
return this.push(buf);
}
n/a
ext_openssh_statvfs = function (path, cb) {
var state = this._state;
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!state.extensions['statvfs@openssh.com']
|| state.extensions['statvfs@openssh.com'].indexOf('2') === -1)
throw new Error('Server does not support this extended request');
/*
uint32 id
string "statvfs@openssh.com"
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + 19 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.EXTENDED;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(19, p, true);
buf.write('statvfs@openssh.com', p += 4, 19, 'ascii');
buf.writeUInt32BE(pathlen, p += 19, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = {
extended: 'statvfs@openssh.com',
cb: cb
};
this.debug('DEBUG[SFTP]: Outgoing: Writing statvfs@openssh.com');
return this.push(buf);
}
n/a
fastGet = function (remotePath, localPath, opts, cb) { if (this.server) throw new Error('Client-only method called in server mode'); fastXfer(this, fs, remotePath, localPath, opts, cb); }
n/a
fastPut = function (localPath, remotePath, opts, cb) { if (this.server) throw new Error('Client-only method called in server mode'); fastXfer(fs, this, localPath, remotePath, opts, cb); }
n/a
fchmod = function (handle, mode, cb) { return this.fsetstat(handle, { mode: mode }, cb); }
n/a
fchown = function (handle, uid, gid, cb) { return this.fsetstat(handle, { uid: uid, gid: gid }, cb); }
n/a
fsetstat = function (handle, attrs, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
var flags = 0;
var attrBytes = 0;
var state = this._state;
if (typeof attrs === 'object') {
attrs = attrsToBytes(attrs);
flags = attrs.flags;
attrBytes = attrs.nbytes;
attrs = attrs.bytes;
} else if (typeof attrs === 'function')
cb = attrs;
/*
uint32 id
string handle
ATTRS attrs
*/
var handlelen = handle.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + handlelen + 4 + attrBytes);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.FSETSTAT;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(handlelen, p, true);
handle.copy(buf, p += 4);
buf.writeUInt32BE(flags, p += handlelen);
if (flags) {
p += 4;
for (var i = 0, len = attrs.length; i < len; ++i)
for (var j = 0, len2 = attrs[i].length; j < len2; ++j)
buf[p++] = attrs[i][j];
}
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing FSETSTAT');
return this.push(buf);
}
n/a
fstat = function (handle, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
var state = this._state;
/*
uint32 id
string handle
*/
var handlelen = handle.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + handlelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.FSTAT;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(handlelen, p, true);
handle.copy(buf, p += 4);
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing FSTAT');
return this.push(buf);
}
n/a
futimes = function (handle, atime, mtime, cb) { return this.fsetstat(handle, { atime: toUnixTimestamp(atime), mtime: toUnixTimestamp(mtime) }, cb); }
n/a
handle = function (id, handle) { if (!this.server) throw new Error('Server-only method called in client mode'); if (!Buffer.isBuffer(handle)) throw new Error('handle is not a Buffer'); var handleLen = handle.length; if (handleLen > 256) throw new Error('handle too large (> 256 bytes)'); var buf = new Buffer(4 + 1 + 4 + 4 + handleLen); buf.writeUInt32BE(buf.length - 4, 0, true); buf[4] = RESPONSE.HANDLE; buf.writeUInt32BE(id, 5, true); buf.writeUInt32BE(handleLen, 9, true); if (handleLen) handle.copy(buf, 13); this.debug('DEBUG[SFTP]: Outgoing: Writing HANDLE'); return this.push(buf); }
n/a
lstat = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.LSTAT;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing LSTAT');
return this.push(buf);
}
n/a
mkdir = function (path, attrs, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var flags = 0;
var attrBytes = 0;
var state = this._state;
if (typeof attrs === 'function') {
cb = attrs;
attrs = undefined;
}
if (typeof attrs === 'object') {
attrs = attrsToBytes(attrs);
flags = attrs.flags;
attrBytes = attrs.nbytes;
attrs = attrs.bytes;
}
/*
uint32 id
string path
ATTRS attrs
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen + 4 + attrBytes);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.MKDIR;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
buf.writeUInt32BE(flags, p += pathlen);
if (flags) {
p += 4;
for (var i = 0, len = attrs.length; i < len; ++i)
for (var j = 0, len2 = attrs[i].length; j < len2; ++j)
buf[p++] = attrs[i][j];
}
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing MKDIR');
return this.push(buf);
}
n/a
name = function (id, names) { if (!this.server) throw new Error('Server-only method called in client mode'); if (!Array.isArray(names) && typeof names === 'object') names = [ names ]; else if (!Array.isArray(names)) throw new Error('names is not an object or array'); var count = names.length; var namesLen = 0; var nameAttrs; var attrs = []; var name; var filename; var longname; var attr; var len; var len2; var buf; var p; var i; var j; var k; for (i = 0; i < count; ++i) { name = names[i]; filename = (!name || !name.filename || typeof name.filename !== 'string' ? '' : name.filename); namesLen += 4 + Buffer.byteLength(filename); longname = (!name || !name.longname || typeof name.longname !== 'string' ? '' : name.longname); namesLen += 4 + Buffer.byteLength(longname); if (typeof name.attrs === 'object') { nameAttrs = attrsToBytes(name.attrs); namesLen += 4 + nameAttrs.nbytes; attrs.push(nameAttrs); } else { namesLen += 4; attrs.push(null); } } buf = new Buffer(4 + 1 + 4 + 4 + namesLen); buf.writeUInt32BE(buf.length - 4, 0, true); buf[4] = RESPONSE.NAME; buf.writeUInt32BE(id, 5, true); buf.writeUInt32BE(count, 9, true); p = 13; for (i = 0; i < count; ++i) { name = names[i]; filename = (!name || !name.filename || typeof name.filename !== 'string' ? '' : name.filename); len = Buffer.byteLength(filename); buf.writeUInt32BE(len, p, true); p += 4; if (len) { buf.write(filename, p, len, 'utf8'); p += len; } longname = (!name || !name.longname || typeof name.longname !== 'string' ? '' : name.longname); len = Buffer.byteLength(longname); buf.writeUInt32BE(len, p, true); p += 4; if (len) { buf.write(longname, p, len, 'utf8'); p += len; } attr = attrs[i]; if (attr) { buf.writeUInt32BE(attr.flags, p, true); p += 4; if (attr.flags && attr.bytes) { var bytes = attr.bytes; for (j = 0, len = bytes.length; j < len; ++j) for (k = 0, len2 = bytes[j].length; k < len2; ++k) buf[p++] = bytes[j][k]; } } else { buf.writeUInt32BE(0, p, true); p += 4; } } this.debug('DEBUG[SFTP]: Outgoing: Writing NAME'); return this.push(buf); }
n/a
open = function (path, flags_, attrs, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
if (typeof attrs === 'function') {
cb = attrs;
attrs = undefined;
}
var flags = stringToFlags(flags_);
if (flags === null)
throw new Error('Unknown flags string: ' + flags_);
var attrFlags = 0;
var attrBytes = 0;
if (typeof attrs === 'string' || typeof attrs === 'number') {
attrs = { mode: attrs };
}
if (typeof attrs === 'object') {
attrs = attrsToBytes(attrs);
attrFlags = attrs.flags;
attrBytes = attrs.nbytes;
attrs = attrs.bytes;
}
/*
uint32 id
string filename
uint32 pflags
ATTRS attrs
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen + 4 + 4 + attrBytes);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.OPEN;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
buf.writeUInt32BE(flags, p += pathlen, true);
buf.writeUInt32BE(attrFlags, p += 4, true);
if (attrs && attrFlags) {
p += 4;
for (var i = 0, len = attrs.length; i < len; ++i)
for (var j = 0, len2 = attrs[i].length; j < len2; ++j)
buf[p++] = attrs[i][j];
}
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing OPEN');
return this.push(buf);
}
n/a
opendir = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.OPENDIR;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing OPENDIR');
return this.push(buf);
}
n/a
push = function (chunk, encoding) { if (!this.readable) return false; if (chunk === null) this.readable = false; var ret = this.__push(chunk, encoding); this._needContinue = (ret === false); return ret; }
...
var SUPPORTED_SERVER_HOST_KEY = [
'ssh-dss'
];
if (semver.gte(process.version, '5.2.0')) {
// ECDSA keys are only supported in v5.2.0+ because of a crypto change that
// made it possible to (efficiently) generate an ECDSA public key from a
// private key (commit nodejs/node#da5ac55c83eb2c09cfb3baf7875529e8f1113529)
DEFAULT_SERVER_HOST_KEY.push(
'ecdsa-sha2-nistp256',
'ecdsa-sha2-nistp384',
'ecdsa-sha2-nistp521'
);
}
var SERVER_HOST_KEY_BUF = new Buffer(DEFAULT_SERVER_HOST_KEY.join(','),
'ascii');
...
readData = function (handle, buf, off, len, position, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
else if (!Buffer.isBuffer(buf))
throw new Error('buffer is not a Buffer');
else if (off >= buf.length)
throw new Error('offset is out of bounds');
else if (off + len > buf.length)
throw new Error('length extends beyond buffer');
else if (position === null)
throw new Error('null position currently unsupported');
var state = this._state;
/*
uint32 id
string handle
uint64 offset
uint32 len
*/
var handlelen = handle.length;
var p = 9;
var pos = position;
var out = new Buffer(4 + 1 + 4 + 4 + handlelen + 8 + 4);
out.writeUInt32BE(out.length - 4, 0, true);
out[4] = REQUEST.READ;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
out.writeUInt32BE(reqid, 5, true);
out.writeUInt32BE(handlelen, p, true);
handle.copy(out, p += 4);
p += handlelen;
for (var i = 7; i >= 0; --i) {
out[p + i] = pos & 0xFF;
pos /= 256;
}
out.writeUInt32BE(len, p += 8, true);
state.requests[reqid] = {
cb: function(err, data, nb) {
if (err && err.code !== STATUS_CODE.EOF)
return cb(err);
cb(undefined, nb || 0, data, position);
},
buffer: buf.slice(off, off + len)
};
this.debug('DEBUG[SFTP]: Outgoing: Writing READ');
return this.push(out);
}
n/a
readFile = function (path, options, callback_) { if (this.server) throw new Error('Client-only method called in server mode'); var callback; if (typeof callback_ === 'function') { callback = callback_; } else if (typeof options === 'function') { callback = options; options = undefined; } var self = this; if (typeof options === 'string') options = { encoding: options, flag: 'r' }; else if (!options) options = { encoding: null, flag: 'r' }; else if (typeof options !== 'object') throw new TypeError('Bad arguments'); var encoding = options.encoding; if (encoding && !Buffer.isEncoding(encoding)) throw new Error('Unknown encoding: ' + encoding); // first, stat the file, so we know the size. var size; var buffer; // single buffer with file data var buffers; // list for when size is unknown var pos = 0; var handle; // SFTPv3 does not support using -1 for read position, so we have to track // read position manually var bytesRead = 0; var flag = options.flag || 'r'; this.open(path, flag, 438 /*=0666*/, function(er, handle_) { if (er) return callback && callback(er); handle = handle_; self.fstat(handle, function tryStat(er, st) { if (er) { // Try stat() for sftp servers that may not support fstat() for // whatever reason self.stat(path, function(er_, st_) { if (er_) { return self.close(handle, function() { callback && callback(er); }); } tryStat(null, st_); }); return; } size = st.size; if (size === 0) { // the kernel lies about many files. // Go ahead and try to read some bytes. buffers = []; return read(); } buffer = new Buffer(size); read(); }); }); function read() { if (size === 0) { buffer = new Buffer(8192); self.readData(handle, buffer, 0, 8192, bytesRead, afterRead); } else self.readData(handle, buffer, pos, size - pos, bytesRead, afterRead); } function afterRead(er, nbytes) { if (er) { return self.close(handle, function() { return callback && callback(er); }); } if (nbytes === 0) return close(); bytesRead += nbytes; pos += nbytes; if (size !== 0) { if (pos === size) close(); else read(); } else { // unknown size, just read until we don't get bytes. buffers.push(buffer.slice(0, nbytes)); read(); } } function close() { self.close(handle, function(er) { if (size === 0) { // collected the data into the buffers list. buffer = Buffer.concat(buffers, pos); } else if (pos < size) buffer = buffer.slice(0, pos); if (encoding) buffer = buffer.toString(encoding); return callback && callback(er, buffer); }); } }
n/a
readdir = function (where, opts, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
var doFilter;
if (typeof opts === 'function') {
cb = opts;
opts = {};
}
if (typeof opts !== 'object')
opts = {};
doFilter = (opts && opts.full ? false : true);
if (!Buffer.isBuffer(where) && typeof where !== 'string')
throw new Error('missing directory handle or path');
if (typeof where === 'string') {
var self = this;
var entries = [];
var e = 0;
return this.opendir(where, function reread(err, handle) {
if (err)
return cb(err);
self.readdir(handle, opts, function(err, list) {
var eof = (err && err.code === STATUS_CODE.EOF);
if (err && !eof) {
return self.close(handle, function() {
cb(err);
});
} else if (eof) {
return self.close(handle, function(err) {
if (err)
return cb(err);
cb(undefined, entries);
});
}
for (var i = 0, len = list.length; i < len; ++i, ++e)
entries[e] = list[i];
reread(undefined, handle);
});
});
}
/*
uint32 id
string handle
*/
var handlelen = where.length;
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + handlelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.READDIR;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(handlelen, p, true);
where.copy(buf, p += 4);
state.requests[reqid] = {
cb: (doFilter
? function(err, list) {
if (err)
return cb(err);
for (var i = list.length - 1; i >= 0; --i) {
if (list[i].filename === '.' || list[i].filename === '..')
list.splice(i, 1);
}
cb(undefined, list);
}
: cb)
};
this.debug('DEBUG[SFTP]: Outgoing: Writing READDIR');
return this.push(buf);
}
n/a
readlink = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.READLINK;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = {
cb: function(err, names) {
if (err)
return cb(err);
else if (!names || !names.length)
return cb(new Error('Response missing link info'));
cb(undefined, names[0].filename);
}
};
this.debug('DEBUG[SFTP]: Outgoing: Writing READLINK');
return this.push(buf);
}
n/a
realpath = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.REALPATH;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = {
cb: function(err, names) {
if (err)
return cb(err);
else if (!names || !names.length)
return cb(new Error('Response missing path info'));
cb(undefined, names[0].filename);
}
};
this.debug('DEBUG[SFTP]: Outgoing: Writing REALPATH');
return this.push(buf);
}
n/a
rename = function (oldPath, newPath, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string oldpath
string newpath
*/
var oldlen = Buffer.byteLength(oldPath);
var newlen = Buffer.byteLength(newPath);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + oldlen + 4 + newlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.RENAME;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(oldlen, p, true);
buf.write(oldPath, p += 4, oldlen, 'utf8');
buf.writeUInt32BE(newlen, p += oldlen, true);
buf.write(newPath, p += 4, newlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing RENAME');
return this.push(buf);
}
n/a
rmdir = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.RMDIR;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing RMDIR');
return this.push(buf);
}
n/a
setstat = function (path, attrs, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var flags = 0;
var attrBytes = 0;
var state = this._state;
if (typeof attrs === 'object') {
attrs = attrsToBytes(attrs);
flags = attrs.flags;
attrBytes = attrs.nbytes;
attrs = attrs.bytes;
} else if (typeof attrs === 'function')
cb = attrs;
/*
uint32 id
string path
ATTRS attrs
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen + 4 + attrBytes);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.SETSTAT;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
buf.writeUInt32BE(flags, p += pathlen);
if (flags) {
p += 4;
for (var i = 0, len = attrs.length; i < len; ++i)
for (var j = 0, len2 = attrs[i].length; j < len2; ++j)
buf[p++] = attrs[i][j];
}
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing SETSTAT');
return this.push(buf);
}
n/a
stat = function (path, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string path
*/
var pathlen = Buffer.byteLength(path);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + pathlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.STAT;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(pathlen, p, true);
buf.write(path, p += 4, pathlen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing STAT');
return this.push(buf);
}
n/a
status = function (id, code, message, lang) { if (!this.server) throw new Error('Server-only method called in client mode'); if (!STATUS_CODE[code] || typeof code !== 'number') throw new Error('Bad status code: ' + code); message || (message = ''); lang || (lang = ''); var msgLen = Buffer.byteLength(message); var langLen = Buffer.byteLength(lang); var buf = new Buffer(4 + 1 + 4 + 4 + 4 + msgLen + 4 + langLen); buf.writeUInt32BE(buf.length - 4, 0, true); buf[4] = RESPONSE.STATUS; buf.writeUInt32BE(id, 5, true); buf.writeUInt32BE(code, 9, true); buf.writeUInt32BE(msgLen, 13, true); if (msgLen) buf.write(message, 17, msgLen, 'utf8'); buf.writeUInt32BE(langLen, 17 + msgLen, true); if (langLen) buf.write(lang, 17 + msgLen + 4, langLen, 'ascii'); this.debug('DEBUG[SFTP]: Outgoing: Writing STATUS'); return this.push(buf); }
n/a
symlink = function (targetPath, linkPath, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string linkpath
string targetpath
*/
var linklen = Buffer.byteLength(linkPath);
var targetlen = Buffer.byteLength(targetPath);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + linklen + 4 + targetlen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.SYMLINK;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
if (this._isOpenSSH) {
// OpenSSH has linkpath and targetpath positions switched
buf.writeUInt32BE(targetlen, p, true);
buf.write(targetPath, p += 4, targetlen, 'utf8');
buf.writeUInt32BE(linklen, p += targetlen, true);
buf.write(linkPath, p += 4, linklen, 'utf8');
} else {
buf.writeUInt32BE(linklen, p, true);
buf.write(linkPath, p += 4, linklen, 'utf8');
buf.writeUInt32BE(targetlen, p += linklen, true);
buf.write(targetPath, p += 4, targetlen, 'utf8');
}
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing SYMLINK');
return this.push(buf);
}
n/a
unlink = function (filename, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
var state = this._state;
/*
uint32 id
string filename
*/
var fnamelen = Buffer.byteLength(filename);
var p = 9;
var buf = new Buffer(4 + 1 + 4 + 4 + fnamelen);
buf.writeUInt32BE(buf.length - 4, 0, true);
buf[4] = REQUEST.REMOVE;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
buf.writeUInt32BE(reqid, 5, true);
buf.writeUInt32BE(fnamelen, p, true);
buf.write(filename, p += 4, fnamelen, 'utf8');
state.requests[reqid] = { cb: cb };
this.debug('DEBUG[SFTP]: Outgoing: Writing REMOVE');
return this.push(buf);
}
n/a
utimes = function (path, atime, mtime, cb) { return this.setstat(path, { atime: toUnixTimestamp(atime), mtime: toUnixTimestamp(mtime) }, cb); }
n/a
writeData = function (handle, buf, off, len, position, cb) {
if (this.server)
throw new Error('Client-only method called in server mode');
else if (!Buffer.isBuffer(handle))
throw new Error('handle is not a Buffer');
else if (!Buffer.isBuffer(buf))
throw new Error('buffer is not a Buffer');
else if (off > buf.length)
throw new Error('offset is out of bounds');
else if (off + len > buf.length)
throw new Error('length extends beyond buffer');
else if (position === null)
throw new Error('null position currently unsupported');
var self = this;
var state = this._state;
if (!len) {
cb && process.nextTick(function() { cb(undefined, 0); });
return;
}
var overflow = (len > state.maxDataLen
? len - state.maxDataLen
: 0);
var origPosition = position;
if (overflow)
len = state.maxDataLen;
/*
uint32 id
string handle
uint64 offset
string data
*/
var handlelen = handle.length;
var p = 9;
var out = new Buffer(4 + 1 + 4 + 4 + handlelen + 8 + 4 + len);
out.writeUInt32BE(out.length - 4, 0, true);
out[4] = REQUEST.WRITE;
var reqid = state.writeReqid = (state.writeReqid + 1) % MAX_REQID;
out.writeUInt32BE(reqid, 5, true);
out.writeUInt32BE(handlelen, p, true);
handle.copy(out, p += 4);
p += handlelen;
for (var i = 7; i >= 0; --i) {
out[p + i] = position & 0xFF;
position /= 256;
}
out.writeUInt32BE(len, p += 8, true);
buf.copy(out, p += 4, off, off + len);
state.requests[reqid] = {
cb: function(err) {
if (err)
cb && cb(err);
else if (overflow) {
self.writeData(handle,
buf,
off + len,
overflow,
origPosition + len,
cb);
} else
cb && cb(undefined, off + len);
}
};
this.debug('DEBUG[SFTP]: Outgoing: Writing WRITE');
return this.push(out);
}
n/a
writeFile = function (path, data, options, callback_) { if (this.server) throw new Error('Client-only method called in server mode'); var callback; if (typeof callback_ === 'function') { callback = callback_; } else if (typeof options === 'function') { callback = options; options = undefined; } var self = this; if (typeof options === 'string') options = { encoding: options, mode: 438, flag: 'w' }; else if (!options) options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' }; else if (typeof options !== 'object') throw new TypeError('Bad arguments'); if (options.encoding && !Buffer.isEncoding(options.encoding)) throw new Error('Unknown encoding: ' + options.encoding); var flag = options.flag || 'w'; this.open(path, flag, options.mode, function(openErr, handle) { if (openErr) callback && callback(openErr); else { var buffer = (Buffer.isBuffer(data) ? data : new Buffer('' + data, options.encoding || 'utf8')); var position = (/a/.test(flag) ? null : 0); // SFTPv3 does not support the notion of 'current position' // (null position), so we just attempt to append to the end of the file // instead if (position === null) { self.fstat(handle, function tryStat(er, st) { if (er) { // Try stat() for sftp servers that may not support fstat() for // whatever reason self.stat(path, function(er_, st_) { if (er_) { return self.close(handle, function() { callback && callback(er); }); } tryStat(null, st_); }); return; } writeAll(self, handle, buffer, 0, buffer.length, st.size, callback); }); return; } writeAll(self, handle, buffer, 0, buffer.length, position, callback); } }); }
n/a
function SSH2Stream(cfg) { if (typeof cfg !== 'object' || cfg === null) cfg = {}; TransformStream.call(this, { highWaterMark: (typeof cfg.highWaterMark === 'number' ? cfg.highWaterMark : 32 * 1024) }); this._needContinue = false; this.bytesSent = this.bytesReceived = 0; this.debug = (typeof cfg.debug === 'function' ? cfg.debug : DEBUG_NOOP); this.server = (cfg.server === true); this.maxPacketSize = (typeof cfg.maxPacketSize === 'number' ? cfg.maxPacketSize : MAX_PACKET_SIZE); // Bitmap that indicates any bugs the remote side has. This is determined // by the reported software version. this.remoteBugs = 0; if (this.server) { // TODO: Remove when we support group exchange for server implementation this.remoteBugs = BUGS.BAD_DHGEX; } var self = this; var hostKeys = cfg.hostKeys; if (this.server && (typeof hostKeys !== 'object' || hostKeys === null)) throw new Error('hostKeys must be an object keyed on host key type'); this.config = { // Server hostKeys: hostKeys, // All keys supported by server // Client/Server ident: 'SSH-2.0-' + (cfg.ident || ('ssh2js' + MODULE_VER + (this.server ? 'srv' : ''))), algorithms: { kex: ALGORITHMS.KEX, kexBuf: ALGORITHMS.KEX_BUF, serverHostKey: ALGORITHMS.SERVER_HOST_KEY, serverHostKeyBuf: ALGORITHMS.SERVER_HOST_KEY_BUF, cipher: ALGORITHMS.CIPHER, cipherBuf: ALGORITHMS.CIPHER_BUF, hmac: ALGORITHMS.HMAC, hmacBuf: ALGORITHMS.HMAC_BUF, compress: ALGORITHMS.COMPRESS, compressBuf: ALGORITHMS.COMPRESS_BUF } }; // RFC 4253 states the identification string must not contain NULL this.config.ident.replace(RE_NULL, ''); if (this.config.ident.length + 2 /* Account for "\r\n" */ > 255) throw new Error('ident too long'); if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algos = cfg.algorithms; if (Array.isArray(algos.kex) && algos.kex.length > 0) { this.config.algorithms.kex = algos.kex; if (!Buffer.isBuffer(algos.kexBuf)) algos.kexBuf = new Buffer(algos.kex.join(','), 'ascii'); this.config.algorithms.kexBuf = algos.kexBuf; } if (Array.isArray(algos.serverHostKey) && algos.serverHostKey.length > 0) { this.config.algorithms.serverHostKey = algos.serverHostKey; if (!Buffer.isBuffer(algos.serverHostKeyBuf)) { algos.serverHostKeyBuf = new Buffer(algos.serverHostKey.join(','), 'ascii'); } this.config.algorithms.serverHostKeyBuf = algos.serverHostKeyBuf; } if (Array.isArray(algos.cipher) && algos.cipher.length > 0) { this.config.algorithms.cipher = algos.cipher; if (!Buffer.isBuffer(algos.cipherBuf)) algos.cipherBuf = new Buffer(algos.cipher.join(','), 'ascii'); this.config.algorithms.cipherBuf = algos.cipherBuf; } if (Array.isArray(algos.hmac) && algos.hmac.length > 0) { this.config.algorithms.hmac = algos.hmac; if (!Buffer.isBuffer(algos.hmacBuf)) algos.hmacBuf = new Buffer(algos.hmac.join(','), 'ascii'); this.config.algorithms.hmacBuf = algos.hmacBuf; } if (Array.isArray(algos.compress) && algos.compress.length > 0) { this.config.algorithms.compress = algos.compress; if (!Buffer.isBuffer(algos.compressBuf)) algos.compressBuf = new Buffer(algos.compress.join(','), 'ascii'); this.config.algorithms.compressBuf = algos.compressBuf; } } this.reset(true); // Common events this.on('end', function() { // Let GC collect any Buffers we were previously storing self._state = undefined; self.reset(); self._state.incoming.hmac.bufCompute = undefined; self._state.outgoing.bufSeqno = undefined; }); this.on('DISCONNECT', function(reason, code, desc, lang) { onDISCONNECT(self, reason, code, desc, lang); }); this.on('KEXINIT', function(init, firstFollows) { onKEXINIT(self, ...
n/a
function send(self, payload, cb, bypass) { var state = self._state; if (!state) return false; var outstate = state.outgoing; if (outstate.status === OUT_REKEYING && !bypass) { if (typeof cb === 'function') outstate.rekeyQueue.push([payload, cb]); else outstate.rekeyQueue.push(payload); return false; } else if (self._readableState.ended || self._writableState.ended) return false; var compress = outstate.compress.instance; if (compress) { compress.write(payload); compress.flush(Z_PARTIAL_FLUSH, function() { if (self._readableState.ended || self._writableState.ended) return; send_(self, compress.read(), cb); }); return true; } else return send_(self, payload, cb); }
n/a
function Transform(options) { if (!(this instanceof Transform)) return new Transform(options); Duplex.call(this, options); this._transformState = new TransformState(this); var stream = this; // start out asking for a readable event once data is transformed. this._readableState.needReadable = true; // we have implemented the _read method, and done the other things // that Readable wants before the first _read call, so unset the // sync guard flag. this._readableState.sync = false; if (options) { if (typeof options.transform === 'function') this._transform = options.transform; if (typeof options.flush === 'function') this._flush = options.flush; } // When the writable side finishes, then flush out anything remaining. this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { done(stream, er); }); else done(stream); }); }
n/a
__push = function (chunk, encoding) { this._transformState.needTransform = false; return Duplex.prototype.push.call(this, chunk, encoding); }
n/a
__read = function (n) { var ts = this._transformState; if (ts.writechunk !== null && ts.writecb && !ts.transforming) { ts.transforming = true; this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else { // mark that we need a transform, so that any data that comes in // will get processed, now that we've asked for it. ts.needTransform = true; } }
n/a
_cleanup = function (callback) { this.reset(); this.debug('DEBUG: Parser: Malformed packet'); callback && callback(new Error('Malformed packet')); }
n/a
_read = function (n) { if (this._needContinue) { this._needContinue = false; this.emit('continue'); } return this.__read(n); }
n/a
_transform = function (chunk, encoding, callback, decomp) { var skipDecrypt = false; var doDecryptGCM = false; var state = this._state; var instate = state.incoming; var outstate = state.outgoing; var expect = instate.expect; var decrypt = instate.decrypt; var decompress = instate.decompress; var chlen = chunk.length; var chleft = 0; var debug = this.debug; var self = this; var i = 0; var p = i; var buffer; var buf; var r; this.bytesReceived += chlen; while (true) { if (expect.type !== undefined) { if (i >= chlen) break; if (expect.type === EXP_TYPE_BYTES) { chleft = (chlen - i); var pktLeft = (expect.buf.length - expect.ptr); if (pktLeft <= chleft) { chunk.copy(expect.buf, expect.ptr, i, i + pktLeft); i += pktLeft; buffer = expect.buf; expect.buf = undefined; expect.ptr = 0; expect.type = undefined; } else { chunk.copy(expect.buf, expect.ptr, i); expect.ptr += chleft; i += chleft; } continue; } else if (expect.type === EXP_TYPE_HEADER) { i += instate.search.push(chunk); if (expect.type !== undefined) continue; } else if (expect.type === EXP_TYPE_LF) { if (++expect.ptr + 4 /* Account for "SSH-" */ > 255) { this.reset(); debug('DEBUG: Parser: Identification string exceeded 255 characters'); return callback(new Error('Max identification string size exceeded')); } if (chunk[i] === 0x0A) { expect.type = undefined; if (p < i) { if (expect.buf === undefined) expect.buf = chunk.toString('ascii', p, i); else expect.buf += chunk.toString('ascii', p, i); } buffer = expect.buf; expect.buf = undefined; ++i; } else { if (++i === chlen && p < i) { if (expect.buf === undefined) expect.buf = chunk.toString('ascii', p, i); else expect.buf += chunk.toString('ascii', p, i); } continue; } } } if (instate.status === IN_INIT) { if (this.server) { // Retrieve what should be the start of the protocol version exchange if (!buffer) { debug('DEBUG: Parser: IN_INIT (waiting for identification begin)'); expectData(this, EXP_TYPE_BYTES, 4); } else { if (buffer[0] === 0x53 // S && buffer[1] === 0x53 // S && buffer[2] === 0x48 // H && buffer[3] === 0x2D) { // - instate.status = IN_GREETING; debug('DEBUG: Parser: IN_INIT (waiting for rest of identification)'); } else { this.reset(); debug('DEBUG: Parser: Bad identification start'); return callback(new Error('Bad identification start')); } } } else { debug('DEBUG: Parser: IN_INIT'); // Retrieve any bytes that may come before the protocol version exchange var ss = instate.search = new StreamSearch(IDENT_PREFIX_BUFFER); ss.on('info', function onInfo(matched, data, start, end) { if (data) { if (instate.greeting === undefined) instate.greeting = data.toString('binary', start, end); else instate.greeting += data.toString('binary', start, end); } if (matched) { expect.type = undefined; instate.search.removeListener('info', onInfo); } }); ss.maxMatches = 1; expectData(this, EXP_TYPE_HEADER); instate.status = IN_GREETING; } } else if (instate.status === IN_GREETING) { debug('DEBUG: Parser: IN_GREETING'); instate.search = undefined; // Retrieve the identification bytes after the "SSH-" header p = i; expectData(this, EXP_TYPE_LF); instate.status = IN_HEADER; } else if (instate.status === ...
n/a
authFailure = function (authMethods, isPartial) { if (!this.server) throw new Error('Server-only method called in client mode'); var authsQueue = this._state.authsQueue; if (!authsQueue.length) throw new Error('No auth in progress'); var methods; if (typeof authMethods === 'boolean') { isPartial = authMethods; authMethods = undefined; } if (authMethods) { methods = []; for (var i = 0, len = authMethods.length; i < len; ++i) { if (authMethods[i].toLowerCase() === 'none') continue; methods.push(authMethods[i]); } methods = methods.join(','); } else methods = ''; var methodsLen = methods.length; var buf = new Buffer(1 + 4 + methodsLen + 1); buf[0] = MESSAGE.USERAUTH_FAILURE; buf.writeUInt32BE(methodsLen, 1, true); buf.write(methods, 5, methodsLen, 'ascii'); buf[5 + methodsLen] = (isPartial === true ? 1 : 0); this._state.authsQueue.shift(); this.debug('DEBUG: Outgoing: Writing USERAUTH_FAILURE'); return send(this, buf); }
n/a
authHostbased = function (username, pubKey, hostname, userlocal, cbSign) { // TODO: Make DRY by sharing similar code with authPK() if (this.server) throw new Error('Client-only method called in server mode'); var self = this; var outstate = this._state.outgoing; var pubKeyFullType; if (pubKey.public) { pubKeyFullType = pubKey.fulltype; pubKey = pubKey.public; } else { pubKeyFullType = pubKey.toString('ascii', 4, 4 + pubKey.readUInt32BE(0, true)); } var userLen = Buffer.byteLength(username); var algoLen = Buffer.byteLength(pubKeyFullType); var pubKeyLen = pubKey.length; var sesLen = outstate.sessionId.length; var hostnameLen = Buffer.byteLength(hostname); var userlocalLen = Buffer.byteLength(userlocal); var p = 0; var buf = new Buffer(4 + sesLen + 1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 9 // "hostbased" + 4 + algoLen + 4 + pubKeyLen + 4 + hostnameLen + 4 + userlocalLen ); buf.writeUInt32BE(sesLen, p, true); outstate.sessionId.copy(buf, p += 4); buf[p += sesLen] = MESSAGE.USERAUTH_REQUEST; buf.writeUInt32BE(userLen, ++p, true); buf.write(username, p += 4, userLen, 'utf8'); buf.writeUInt32BE(14, p += userLen, true); buf.write('ssh-connection', p += 4, 14, 'ascii'); buf.writeUInt32BE(9, p += 14, true); buf.write('hostbased', p += 4, 9, 'ascii'); buf.writeUInt32BE(algoLen, p += 9, true); buf.write(pubKeyFullType, p += 4, algoLen, 'ascii'); buf.writeUInt32BE(pubKeyLen, p += algoLen, true); pubKey.copy(buf, p += 4); buf.writeUInt32BE(hostnameLen, p += pubKeyLen, true); buf.write(hostname, p += 4, hostnameLen, 'ascii'); buf.writeUInt32BE(userlocalLen, p += hostnameLen, true); buf.write(userlocal, p += 4, userlocalLen, 'utf8'); cbSign(buf, function(signature) { if (pubKeyFullType === 'ssh-dss') { signature = DSASigBERToBare(signature); } else if (pubKeyFullType !== 'ssh-rsa') { // ECDSA signature = ECDSASigASN1ToSSH(signature); } var sigLen = signature.length; var sigbuf = new Buffer((buf.length - sesLen) + sigLen); buf.copy(sigbuf, 0, 4 + sesLen); sigbuf.writeUInt32BE(sigLen, sigbuf.length - sigLen - 4, true); signature.copy(sigbuf, sigbuf.length - sigLen); self._state.authsQueue.push('hostbased'); self.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (hostbased)'); return send(self, sigbuf); }); return true; }
n/a
authInfoReq = function (name, instructions, prompts) { if (!this.server) throw new Error('Server-only method called in client mode'); var promptsLen = 0; var nameLen = name ? Buffer.byteLength(name) : 0; var instrLen = instructions ? Buffer.byteLength(instructions) : 0; var p = 0; var promptLen; var prompt; var len; var i; for (i = 0, len = prompts.length; i < len; ++i) promptsLen += 4 + Buffer.byteLength(prompts[i].prompt) + 1; var buf = new Buffer(1 + 4 + nameLen + 4 + instrLen + 4 + 4 + promptsLen); buf[p++] = MESSAGE.USERAUTH_INFO_REQUEST; buf.writeUInt32BE(nameLen, p, true); p += 4; if (name) { buf.write(name, p, nameLen, 'utf8'); p += nameLen; } buf.writeUInt32BE(instrLen, p, true); p += 4; if (instructions) { buf.write(instructions, p, instrLen, 'utf8'); p += instrLen; } buf.writeUInt32BE(0, p, true); p += 4; buf.writeUInt32BE(prompts.length, p, true); p += 4; for (i = 0, len = prompts.length; i < len; ++i) { prompt = prompts[i]; promptLen = Buffer.byteLength(prompt.prompt); buf.writeUInt32BE(promptLen, p, true); p += 4; if (promptLen) { buf.write(prompt.prompt, p, promptLen, 'utf8'); p += promptLen; } buf[p++] = (prompt.echo ? 1 : 0); } this.debug('DEBUG: Outgoing: Writing USERAUTH_INFO_REQUEST'); return send(this, buf); }
n/a
authInfoRes = function (responses) { if (this.server) throw new Error('Client-only method called in server mode'); var responsesLen = 0; var p = 0; var resLen; var len; var i; if (responses) { for (i = 0, len = responses.length; i < len; ++i) responsesLen += 4 + Buffer.byteLength(responses[i]); } var buf = new Buffer(1 + 4 + responsesLen); buf[p++] = MESSAGE.USERAUTH_INFO_RESPONSE; buf.writeUInt32BE(responses ? responses.length : 0, p, true); if (responses) { p += 4; for (i = 0, len = responses.length; i < len; ++i) { resLen = Buffer.byteLength(responses[i]); buf.writeUInt32BE(resLen, p, true); p += 4; if (resLen) { buf.write(responses[i], p, resLen, 'utf8'); p += resLen; } } } this.debug('DEBUG: Outgoing: Writing USERAUTH_INFO_RESPONSE'); return send(this, buf); }
n/a
authKeyboard = function (username) { if (this.server) throw new Error('Client-only method called in server mode'); var userLen = Buffer.byteLength(username); var p = 0; var buf = new Buffer(1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 20 // "keyboard-interactive" + 4 // no language set + 4 // no submethods ); buf[p] = MESSAGE.USERAUTH_REQUEST; buf.writeUInt32BE(userLen, ++p, true); buf.write(username, p += 4, userLen, 'utf8'); buf.writeUInt32BE(14, p += userLen, true); buf.write('ssh-connection', p += 4, 14, 'ascii'); buf.writeUInt32BE(20, p += 14, true); buf.write('keyboard-interactive', p += 4, 20, 'ascii'); buf.writeUInt32BE(0, p += 20, true); buf.writeUInt32BE(0, p += 4, true); this._state.authsQueue.push('keyboard-interactive'); this.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (keyboard-interactive)'); return send(this, buf); }
n/a
authNone = function (username) { if (this.server) throw new Error('Client-only method called in server mode'); var userLen = Buffer.byteLength(username); var p = 0; var buf = new Buffer(1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 4 // "none" ); buf[p] = MESSAGE.USERAUTH_REQUEST; buf.writeUInt32BE(userLen, ++p, true); buf.write(username, p += 4, userLen, 'utf8'); buf.writeUInt32BE(14, p += userLen, true); buf.write('ssh-connection', p += 4, 14, 'ascii'); buf.writeUInt32BE(4, p += 14, true); buf.write('none', p += 4, 4, 'ascii'); this._state.authsQueue.push('none'); this.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (none)'); return send(this, buf); }
n/a
authPK = function (username, pubKey, cbSign) { if (this.server) throw new Error('Client-only method called in server mode'); var self = this; var outstate = this._state.outgoing; var pubKeyFullType; if (pubKey.public) { pubKeyFullType = pubKey.fulltype; pubKey = pubKey.public; } else { pubKeyFullType = pubKey.toString('ascii', 4, 4 + pubKey.readUInt32BE(0, true)); } var userLen = Buffer.byteLength(username); var algoLen = Buffer.byteLength(pubKeyFullType); var pubKeyLen = pubKey.length; var sesLen = outstate.sessionId.length; var p = 0; var buf = new Buffer((cbSign ? 4 + sesLen : 0) + 1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 9 // "publickey" + 1 + 4 + algoLen + 4 + pubKeyLen ); if (cbSign) { buf.writeUInt32BE(sesLen, p, true); outstate.sessionId.copy(buf, p += 4); buf[p += sesLen] = MESSAGE.USERAUTH_REQUEST; } else buf[p] = MESSAGE.USERAUTH_REQUEST; buf.writeUInt32BE(userLen, ++p, true); buf.write(username, p += 4, userLen, 'utf8'); buf.writeUInt32BE(14, p += userLen, true); buf.write('ssh-connection', p += 4, 14, 'ascii'); buf.writeUInt32BE(9, p += 14, true); buf.write('publickey', p += 4, 9, 'ascii'); buf[p += 9] = (cbSign ? 1 : 0); buf.writeUInt32BE(algoLen, ++p, true); buf.write(pubKeyFullType, p += 4, algoLen, 'ascii'); buf.writeUInt32BE(pubKeyLen, p += algoLen, true); pubKey.copy(buf, p += 4); if (!cbSign) { this._state.authsQueue.push('publickey'); this.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (publickey -- check)'); return send(this, buf); } cbSign(buf, function(signature) { if (pubKeyFullType === 'ssh-dss') { signature = DSASigBERToBare(signature); } else if (pubKeyFullType !== 'ssh-rsa') { // ECDSA signature = ECDSASigASN1ToSSH(signature); } var sigLen = signature.length; var sigbuf = new Buffer(1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 9 // "publickey" + 1 + 4 + algoLen + 4 + pubKeyLen + 4 // 4 + algoLen + 4 + sigLen + 4 + algoLen + 4 + sigLen); p = 0; sigbuf[p] = MESSAGE.USERAUTH_REQUEST; sigbuf.writeUInt32BE(userLen, ++p, true); sigbuf.write(username, p += 4, userLen, 'utf8'); sigbuf.writeUInt32BE(14, p += userLen, true); sigbuf.write('ssh-connection', p += 4, 14, 'ascii'); sigbuf.writeUInt32BE(9, p += 14, true); sigbuf.write('publickey', p += 4, 9, 'ascii'); sigbuf[p += 9] = 1; sigbuf.writeUInt32BE(algoLen, ++p, true); sigbuf.write(pubKeyFullType, p += 4, algoLen, 'ascii'); sigbuf.writeUInt32BE(pubKeyLen, p += algoLen, true); pubKey.copy(sigbuf, p += 4); sigbuf.writeUInt32BE(4 + algoLen + 4 + sigLen, p += pubKeyLen, true); sigbuf.writeUInt32BE(algoLen, p += 4, true); sigbuf.write(pubKeyFullType, p += 4, algoLen, 'ascii'); sigbuf.writeUInt32BE(sigLen, p += algoLen, true); signature.copy(sigbuf, p += 4); // Servers shouldn't send packet type 60 in response to signed publickey // attempts, but if they do, interpret as type 60. self._state.authsQueue.push('publickey'); self.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (publickey)'); return send(self, sigbuf); }); return true; }
n/a
authPKOK = function (keyAlgo, key) { if (!this.server) throw new Error('Server-only method called in client mode'); var authsQueue = this._state.authsQueue; if (!authsQueue.length || authsQueue[0] !== 'publickey') throw new Error('"publickey" auth not in progress'); var keyAlgoLen = keyAlgo.length; var keyLen = key.length; var buf = new Buffer(1 + 4 + keyAlgoLen + 4 + keyLen); buf[0] = MESSAGE.USERAUTH_PK_OK; buf.writeUInt32BE(keyAlgoLen, 1, true); buf.write(keyAlgo, 5, keyAlgoLen, 'ascii'); buf.writeUInt32BE(keyLen, 5 + keyAlgoLen, true); key.copy(buf, 5 + keyAlgoLen + 4); this._state.authsQueue.shift(); this.debug('DEBUG: Outgoing: Writing USERAUTH_PK_OK'); return send(this, buf); }
n/a
authPasswdChg = function (prompt, lang) { if (!this.server) throw new Error('Server-only method called in client mode'); var promptLen = Buffer.byteLength(prompt); var langLen = lang ? lang.length : 0; var p = 0; var buf = new Buffer(1 + 4 + promptLen + 4 + langLen); buf[p] = MESSAGE.USERAUTH_PASSWD_CHANGEREQ; buf.writeUInt32BE(promptLen, ++p, true); buf.write(prompt, p += 4, promptLen, 'utf8'); buf.writeUInt32BE(langLen, p += promptLen, true); if (langLen) buf.write(lang, p += 4, langLen, 'ascii'); this.debug('DEBUG: Outgoing: Writing USERAUTH_PASSWD_CHANGEREQ'); return send(this, buf); }
n/a
authPassword = function (username, password) { if (this.server) throw new Error('Client-only method called in server mode'); var userLen = Buffer.byteLength(username); var passLen = Buffer.byteLength(password); var p = 0; var buf = new Buffer(1 + 4 + userLen + 4 + 14 // "ssh-connection" + 4 + 8 // "password" + 1 + 4 + passLen); buf[p] = MESSAGE.USERAUTH_REQUEST; buf.writeUInt32BE(userLen, ++p, true); buf.write(username, p += 4, userLen, 'utf8'); buf.writeUInt32BE(14, p += userLen, true); buf.write('ssh-connection', p += 4, 14, 'ascii'); buf.writeUInt32BE(8, p += 14, true); buf.write('password', p += 4, 8, 'ascii'); buf[p += 8] = 0; buf.writeUInt32BE(passLen, ++p, true); buf.write(password, p += 4, passLen, 'utf8'); this._state.authsQueue.push('password'); this.debug('DEBUG: Outgoing: Writing USERAUTH_REQUEST (password)'); return send(this, buf); }
n/a
authSuccess = function () { if (!this.server) throw new Error('Server-only method called in client mode'); var authsQueue = this._state.authsQueue; if (!authsQueue.length) throw new Error('No auth in progress'); this._state.authsQueue.shift(); this.debug('DEBUG: Outgoing: Writing USERAUTH_SUCCESS'); return send(this, USERAUTH_SUCCESS_PACKET); }
n/a
cancelTcpipForward = function (bindAddr, bindPort, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); var addrlen = Buffer.byteLength(bindAddr); var buf = new Buffer(1 + 4 + 20 + 1 + 4 + addrlen + 4); buf[0] = MESSAGE.GLOBAL_REQUEST; buf.writeUInt32BE(20, 1, true); buf.write('cancel-tcpip-forward', 5, 20, 'ascii'); buf[25] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(addrlen, 26, true); buf.write(bindAddr, 30, addrlen, 'ascii'); buf.writeUInt32BE(bindPort, 30 + addrlen, true); this.debug('DEBUG: Outgoing: Writing GLOBAL_REQUEST (cancel-tcpip-forward)'); return send(this, buf); }
n/a
channelClose = function (chan) { // Does not consume window space var buf = new Buffer(1 + 4); buf[0] = MESSAGE.CHANNEL_CLOSE; buf.writeUInt32BE(chan, 1, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_CLOSE (' + chan + ')'); return send(this, buf); }
n/a
channelData = function (chan, data) { var dataIsBuffer = Buffer.isBuffer(data); var dataLen = (dataIsBuffer ? data.length : Buffer.byteLength(data)); var buf = new Buffer(1 + 4 + 4 + dataLen); buf[0] = MESSAGE.CHANNEL_DATA; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(dataLen, 5, true); if (dataIsBuffer) data.copy(buf, 9); else buf.write(data, 9, dataLen, 'utf8'); this.debug('DEBUG: Outgoing: Writing CHANNEL_DATA (' + chan + ')'); return send(this, buf); }
n/a
channelEOF = function (chan) { // Does not consume window space var buf = new Buffer(1 + 4); buf[0] = MESSAGE.CHANNEL_EOF; buf.writeUInt32BE(chan, 1, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_EOF (' + chan + ')'); return send(this, buf); }
n/a
channelExtData = function (chan, data, type) { var dataIsBuffer = Buffer.isBuffer(data); var dataLen = (dataIsBuffer ? data.length : Buffer.byteLength(data)); var buf = new Buffer(1 + 4 + 4 + 4 + dataLen); buf[0] = MESSAGE.CHANNEL_EXTENDED_DATA; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(type, 5, true); buf.writeUInt32BE(dataLen, 9, true); if (dataIsBuffer) data.copy(buf, 13); else buf.write(data, 13, dataLen, 'utf8'); this.debug('DEBUG: Outgoing: Writing CHANNEL_EXTENDED_DATA (' + chan + ')'); return send(this, buf); }
n/a
channelFailure = function (chan) { // Does not consume window space var buf = new Buffer(1 + 4); buf[0] = MESSAGE.CHANNEL_FAILURE; buf.writeUInt32BE(chan, 1, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_FAILURE (' + chan + ')'); return send(this, buf); }
n/a
channelOpenConfirm = function (remoteChan, localChan, initWindow, maxPacket) { var buf = new Buffer(1 + 4 + 4 + 4 + 4); buf[0] = MESSAGE.CHANNEL_OPEN_CONFIRMATION; buf.writeUInt32BE(remoteChan, 1, true); buf.writeUInt32BE(localChan, 5, true); buf.writeUInt32BE(initWindow, 9, true); buf.writeUInt32BE(maxPacket, 13, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN_CONFIRMATION (r:' + remoteChan + ', l:' + localChan + ')'); return send(this, buf); }
n/a
channelOpenFail = function (remoteChan, reason, desc, lang) { if (typeof desc !== 'string') desc = ''; if (typeof lang !== 'string') lang = ''; var descLen = Buffer.byteLength(desc); var langLen = Buffer.byteLength(lang); var p = 9; var buf = new Buffer(1 + 4 + 4 + 4 + descLen + 4 + langLen); buf[0] = MESSAGE.CHANNEL_OPEN_FAILURE; buf.writeUInt32BE(remoteChan, 1, true); buf.writeUInt32BE(reason, 5, true); buf.writeUInt32BE(descLen, p, true); p += 4; if (descLen) { buf.write(desc, p, descLen, 'utf8'); p += descLen; } buf.writeUInt32BE(langLen, p, true); if (langLen) buf.write(lang, p += 4, langLen, 'ascii'); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN_FAILURE (' + remoteChan + ')'); return send(this, buf); }
n/a
channelSuccess = function (chan) { // Does not consume window space var buf = new Buffer(1 + 4); buf[0] = MESSAGE.CHANNEL_SUCCESS; buf.writeUInt32BE(chan, 1, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_SUCCESS (' + chan + ')'); return send(this, buf); }
n/a
channelWindowAdjust = function (chan, amount) { // Does not consume window space var buf = new Buffer(1 + 4 + 4); buf[0] = MESSAGE.CHANNEL_WINDOW_ADJUST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(amount, 5, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_WINDOW_ADJUST (' + chan + ', ' + amount + ')'); return send(this, buf); }
n/a
directTcpip = function (chan, initWindow, maxPacket, cfg) { if (this.server) throw new Error('Client-only method called in server mode'); var srclen = Buffer.byteLength(cfg.srcIP); var dstlen = Buffer.byteLength(cfg.dstIP); var p = 29; var buf = new Buffer(1 + 4 + 12 + 4 + 4 + 4 + 4 + srclen + 4 + 4 + dstlen + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(12, 1, true); buf.write('direct-tcpip', 5, 12, 'ascii'); buf.writeUInt32BE(chan, 17, true); buf.writeUInt32BE(initWindow, 21, true); buf.writeUInt32BE(maxPacket, 25, true); buf.writeUInt32BE(dstlen, p, true); buf.write(cfg.dstIP, p += 4, dstlen, 'ascii'); buf.writeUInt32BE(cfg.dstPort, p += dstlen, true); buf.writeUInt32BE(srclen, p += 4, true); buf.write(cfg.srcIP, p += 4, srclen, 'ascii'); buf.writeUInt32BE(cfg.srcPort, p += srclen, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', direct-tcpip)'); return send(this, buf); }
n/a
disconnect = function (reason) {
/*
byte SSH_MSG_DISCONNECT
uint32 reason code
string description in ISO-10646 UTF-8 encoding
string language tag
*/
var buf = new Buffer(1 + 4 + 4 + 4);
buf.fill(0);
buf[0] = MESSAGE.DISCONNECT;
if (DISCONNECT_REASON[reason] === undefined)
reason = DISCONNECT_REASON.BY_APPLICATION;
buf.writeUInt32BE(reason, 1, true);
this.debug('DEBUG: Outgoing: Writing DISCONNECT ('
+ DISCONNECT_REASON[reason]
+ ')');
send(this, buf);
this.reset();
return false;
}
n/a
env = function (chan, key, val, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var keyLen = Buffer.byteLength(key); var valLen = (Buffer.isBuffer(val) ? val.length : Buffer.byteLength(val)); var buf = new Buffer(1 + 4 + 4 + 3 + 1 + 4 + keyLen + 4 + valLen); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(3, 5, true); buf.write('env', 9, 3, 'ascii'); buf[12] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(keyLen, 13, true); buf.write(key, 17, keyLen, 'ascii'); buf.writeUInt32BE(valLen, 17 + keyLen, true); if (Buffer.isBuffer(val)) val.copy(buf, 17 + keyLen + 4); else buf.write(val, 17 + keyLen + 4, valLen, 'utf8'); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', env)'); return send(this, buf); }
n/a
exec = function (chan, cmd, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var cmdlen = (Buffer.isBuffer(cmd) ? cmd.length : Buffer.byteLength(cmd)); var buf = new Buffer(1 + 4 + 4 + 4 + 1 + 4 + cmdlen); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(4, 5, true); buf.write('exec', 9, 4, 'ascii'); buf[13] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(cmdlen, 14, true); if (Buffer.isBuffer(cmd)) cmd.copy(buf, 18); else buf.write(cmd, 18, cmdlen, 'utf8'); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', exec)'); return send(this, buf); }
...
while (!data[0].length)
data.shift();
while (!data.slice(-1)[0].length)
data.pop();
var orig = data.join('\n');
if ((m = RE_HEADER_OPENSSH_PRIV.exec(data[0]))
&& RE_FOOTER_OPENSSH_PRIV.test(data.slice(-1))) {
// OpenSSH private key
var keyType = m[1].toLowerCase();
if (keyType === 'dsa')
keyType = 'dss';
if (keyType === 'ec' && semver.lt(process.version, '5.2.0')) {
...
exitSignal = function (chan, name, coreDumped, msg) { if (!this.server) throw new Error('Server-only method called in client mode'); // Does not consume window space var nameLen = Buffer.byteLength(name); var msgLen = (msg ? Buffer.byteLength(msg) : 0); var p = 25 + nameLen; var buf = new Buffer(1 + 4 + 4 + 11 + 1 + 4 + nameLen + 1 + 4 + msgLen + 4); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(11, 5, true); buf.write('exit-signal', 9, 11, 'ascii'); buf[20] = 0; buf.writeUInt32BE(nameLen, 21, true); buf.write(name, 25, nameLen, 'utf8'); buf[p++] = (coreDumped ? 1 : 0); buf.writeUInt32BE(msgLen, p, true); p += 4; if (msgLen) { buf.write(msg, p, msgLen, 'utf8'); p += msgLen; } buf.writeUInt32BE(0, p, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', exit-signal)'); return send(this, buf); }
n/a
exitStatus = function (chan, status) { if (!this.server) throw new Error('Server-only method called in client mode'); // Does not consume window space var buf = new Buffer(1 + 4 + 4 + 11 + 1 + 4); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(11, 5, true); buf.write('exit-status', 9, 11, 'ascii'); buf[20] = 0; buf.writeUInt32BE(status, 21, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', exit-status)'); return send(this, buf); }
n/a
forwardedTcpip = function (chan, initWindow, maxPacket, cfg) { if (!this.server) throw new Error('Server-only method called in client mode'); var boundAddrLen = Buffer.byteLength(cfg.boundAddr); var remoteAddrLen = Buffer.byteLength(cfg.remoteAddr); var p = 36 + boundAddrLen; var buf = new Buffer(1 + 4 + 15 + 4 + 4 + 4 + 4 + boundAddrLen + 4 + 4 + remoteAddrLen + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(15, 1, true); buf.write('forwarded-tcpip', 5, 15, 'ascii'); buf.writeUInt32BE(chan, 20, true); buf.writeUInt32BE(initWindow, 24, true); buf.writeUInt32BE(maxPacket, 28, true); buf.writeUInt32BE(boundAddrLen, 32, true); buf.write(cfg.boundAddr, 36, boundAddrLen, 'ascii'); buf.writeUInt32BE(cfg.boundPort, p, true); buf.writeUInt32BE(remoteAddrLen, p += 4, true); buf.write(cfg.remoteAddr, p += 4, remoteAddrLen, 'ascii'); buf.writeUInt32BE(cfg.remotePort, p += remoteAddrLen, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', forwarded-tcpip)'); return send(this, buf); }
n/a
openssh_agentForward = function (chan, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var buf = new Buffer(1 + 4 + 4 + 26 + 1); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(26, 5, true); buf.write('auth-agent-req@openssh.com', 9, 26, 'ascii'); buf[35] = (wantReply === undefined || wantReply === true ? 1 : 0); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', auth-agent-req@openssh.com)'); return send(this, buf); }
n/a
openssh_cancelStreamLocalForward = function (socketPath, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); var pathlen = Buffer.byteLength(pathlen); var buf = new Buffer(1 + 4 + 38 + 1 + 4 + pathlen); buf[0] = MESSAGE.GLOBAL_REQUEST; buf.writeUInt32BE(38, 1, true); buf.write('cancel-streamlocal-forward@openssh.com', 5, 38, 'ascii'); buf[43] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(pathlen, 44, true); buf.write(socketPath, 48, pathlen, 'utf8'); this.debug('DEBUG: Outgoing: Writing GLOBAL_REQUEST (cancel-streamlocal-forward@openssh.com)'); return send(this, buf); }
n/a
openssh_directStreamLocal = function (chan, initWindow, maxPacket, cfg) { if (this.server) throw new Error('Client-only method called in server mode'); var pathlen = Buffer.byteLength(cfg.socketPath); var p = 47; var buf = new Buffer(1 + 4 + 30 + 4 + 4 + 4 + 4 + pathlen + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(30, 1, true); buf.write('direct-streamlocal@openssh.com', 5, 30, 'ascii'); buf.writeUInt32BE(chan, 35, true); buf.writeUInt32BE(initWindow, 39, true); buf.writeUInt32BE(maxPacket, 43, true); buf.writeUInt32BE(pathlen, p, true); buf.write(cfg.socketPath, p += 4, pathlen, 'utf8'); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', direct-streamlocal@openssh.com)'); return send(this, buf); }
n/a
openssh_forwardedStreamLocal = function (chan, initWindow, maxPacket, cfg) { if (!this.server) throw new Error('Server-only method called in client mode'); var pathlen = Buffer.byteLength(cfg.socketPath); var buf = new Buffer(1 + 4 + 33 + 4 + 4 + 4 + 4 + pathlen + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(33, 1, true); buf.write('forwarded-streamlocal@openssh.com', 5, 33, 'ascii'); buf.writeUInt32BE(chan, 38, true); buf.writeUInt32BE(initWindow, 42, true); buf.writeUInt32BE(maxPacket, 46, true); buf.writeUInt32BE(pathlen, 50, true); buf.write(cfg.socketPath, 54, pathlen, 'utf8'); buf.writeUInt32BE(0, 54 + pathlen, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', forwarded-streamlocal@openssh.com)'); return send(this, buf); }
n/a
openssh_noMoreSessions = function (wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); var buf = new Buffer(1 + 4 + 28 + 1); buf[0] = MESSAGE.GLOBAL_REQUEST; buf.writeUInt32BE(28, 1, true); buf.write('no-more-sessions@openssh.com', 5, 28, 'ascii'); buf[33] = (wantReply === undefined || wantReply === true ? 1 : 0); this.debug('DEBUG: Outgoing: Writing GLOBAL_REQUEST (no-more-sessions@openssh.com)'); return send(this, buf); }
n/a
openssh_streamLocalForward = function (socketPath, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); var pathlen = Buffer.byteLength(pathlen); var buf = new Buffer(1 + 4 + 31 + 1 + 4 + pathlen); buf[0] = MESSAGE.GLOBAL_REQUEST; buf.writeUInt32BE(31, 1, true); buf.write('streamlocal-forward@openssh.com', 5, 31, 'ascii'); buf[36] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(pathlen, 37, true); buf.write(socketPath, 41, pathlen, 'utf8'); this.debug('DEBUG: Outgoing: Writing GLOBAL_REQUEST (streamlocal-forward@openssh.com)'); return send(this, buf); }
n/a
ping = function () { this.debug('DEBUG: Outgoing: Writing ping (GLOBAL_REQUEST: keepalive@openssh.com)'); return send(this, PING_PACKET); }
n/a
pty = function (chan, rows, cols, height, width, term, modes, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space if (!term || !term.length) term = 'vt100'; if (modes && !Buffer.isBuffer(modes) && !Array.isArray(modes) && typeof modes === 'object') modes = modesToBytes(modes); if (!modes || !modes.length) modes = NO_TERMINAL_MODES_BUFFER; var termLen = term.length; var modesLen = modes.length; var p = 21; var buf = new Buffer(1 + 4 + 4 + 7 + 1 + 4 + termLen + 4 + 4 + 4 + 4 + 4 + modesLen); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(7, 5, true); buf.write('pty-req', 9, 7, 'ascii'); buf[16] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(termLen, 17, true); buf.write(term, 21, termLen, 'utf8'); buf.writeUInt32BE(cols, p += termLen, true); buf.writeUInt32BE(rows, p += 4, true); buf.writeUInt32BE(width, p += 4, true); buf.writeUInt32BE(height, p += 4, true); buf.writeUInt32BE(modesLen, p += 4, true); p += 4; if (Array.isArray(modes)) { for (var i = 0; i < modesLen; ++i) buf[p++] = modes[i]; } else if (Buffer.isBuffer(modes)) { modes.copy(buf, p); } this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', pty-req)'); return send(this, buf); }
n/a
push = function (chunk, encoding) { var ret = this.__push(chunk, encoding); this._needContinue = (ret === false); return ret; }
...
var SUPPORTED_SERVER_HOST_KEY = [
'ssh-dss'
];
if (semver.gte(process.version, '5.2.0')) {
// ECDSA keys are only supported in v5.2.0+ because of a crypto change that
// made it possible to (efficiently) generate an ECDSA public key from a
// private key (commit nodejs/node#da5ac55c83eb2c09cfb3baf7875529e8f1113529)
DEFAULT_SERVER_HOST_KEY.push(
'ecdsa-sha2-nistp256',
'ecdsa-sha2-nistp384',
'ecdsa-sha2-nistp521'
);
}
var SERVER_HOST_KEY_BUF = new Buffer(DEFAULT_SERVER_HOST_KEY.join(','),
'ascii');
...
rekey = function () { var status = this._state.outgoing.status; if (status === OUT_REKEYING) throw new Error('A re-key is already in progress'); else if (status !== OUT_READY) throw new Error('Cannot re-key yet'); this.debug('DEBUG: Outgoing: Starting re-key'); return KEXINIT(this); }
n/a
requestFailure = function () { this.debug('DEBUG: Outgoing: Writing REQUEST_FAILURE'); return send(this, REQUEST_FAILURE_PACKET); }
n/a
requestSuccess = function (data) { var buf; if (Buffer.isBuffer(data)) { buf = new Buffer(1 + data.length); buf[0] = MESSAGE.REQUEST_SUCCESS; data.copy(buf, 1); } else buf = REQUEST_SUCCESS_PACKET; this.debug('DEBUG: Outgoing: Writing REQUEST_SUCCESS'); return send(this, buf); }
n/a
reset = function (noend) { if (this._state) { var state = this._state; state.incoming.status = IN_INIT; state.outgoing.status = OUT_INIT; } else { this._state = { authsQueue: [], hostkeyFormat: undefined, kex: undefined, kexdh: undefined, incoming: { status: IN_INIT, expectedPacket: undefined, search: undefined, greeting: undefined, seqno: 0, pktLen: undefined, padLen: undefined, pktExtra: undefined, payload: undefined, packet: undefined, kexinit: undefined, identRaw: undefined, rekeyQueue: [], ignoreNext: false, expect: { amount: undefined, type: undefined, ptr: 0, buf: undefined }, decrypt: { instance: false, size: 8, isGCM: false, iv: undefined, // GCM key: undefined, // GCM buf: undefined, type: undefined }, hmac: { size: undefined, key: undefined, buf: undefined, bufCompute: new Buffer(9), type: false }, decompress: { instance: false, type: false } }, outgoing: { status: OUT_INIT, seqno: 0, bufSeqno: new Buffer(4), rekeyQueue: [], kexinit: undefined, kexsecret: undefined, pubkey: undefined, exchangeHash: undefined, sessionId: undefined, sentNEWKEYS: false, encrypt: { instance: false, size: 8, isGCM: false, iv: undefined, // GCM key: undefined, // GCM type: undefined }, hmac: { size: undefined, key: undefined, buf: undefined, type: false }, compress: { instance: false, type: false } } }; } if (!noend) { if (this.readable) this.push(null); } }
n/a
service = function (svcName) { if (this.server) throw new Error('Client-only method called in server mode'); var svcNameLen = Buffer.byteLength(svcName); var buf = new Buffer(1 + 4 + svcNameLen); buf[0] = MESSAGE.SERVICE_REQUEST; buf.writeUInt32BE(svcNameLen, 1, true); buf.write(svcName, 5, svcNameLen, 'ascii'); this.debug('DEBUG: Outgoing: Writing SERVICE_REQUEST (' + svcName + ')'); return send(this, buf); }
n/a
serviceAccept = function (svcName) {
if (!this.server)
throw new Error('Server-only method called in client mode');
var svcNameLen = svcName.length;
var buf = new Buffer(1 + 4 + svcNameLen);
buf[0] = MESSAGE.SERVICE_ACCEPT;
buf.writeUInt32BE(svcNameLen, 1, true);
buf.write(svcName, 5, svcNameLen, 'ascii');
this.debug('DEBUG: Outgoing: Writing SERVICE_ACCEPT (' + svcName + ')');
send(this, buf);
if (this.server && this.banner && svcName === 'ssh-userauth') {
/*
byte SSH_MSG_USERAUTH_BANNER
string message in ISO-10646 UTF-8 encoding
string language tag
*/
var bannerLen = Buffer.byteLength(this.banner);
var packetLen = 1 + 4 + bannerLen + 4;
if (packetLen > BUFFER_MAX_LEN) {
bannerLen -= 1 + 4 + 4;
packetLen -= 1 + 4 + 4;
}
var packet = new Buffer(packetLen);
packet[0] = MESSAGE.USERAUTH_BANNER;
packet.writeUInt32BE(bannerLen, 1, true);
packet.write(this.banner, 5, bannerLen, 'utf8');
packet.fill(0, packetLen - 4); // Empty language tag
this.debug('DEBUG: Outgoing: Writing USERAUTH_BANNER');
send(this, packet);
this.banner = undefined; // Prevent banner from being displayed again
}
}
n/a
session = function (chan, initWindow, maxPacket) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var buf = new Buffer(1 + 4 + 7 + 4 + 4 + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(7, 1, true); buf.write('session', 5, 7, 'ascii'); buf.writeUInt32BE(chan, 12, true); buf.writeUInt32BE(initWindow, 16, true); buf.writeUInt32BE(maxPacket, 20, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', session)'); return send(this, buf); }
n/a
shell = function (chan, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var buf = new Buffer(1 + 4 + 4 + 5 + 1); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(5, 5, true); buf.write('shell', 9, 5, 'ascii'); buf[14] = (wantReply === undefined || wantReply === true ? 1 : 0); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', shell)'); return send(this, buf); }
n/a
signal = function (chan, signal) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space signal = signal.toUpperCase(); if (signal.slice(0, 3) === 'SIG') signal = signal.substring(3); if (SIGNALS.indexOf(signal) === -1) throw new Error('Invalid signal: ' + signal); var signalLen = signal.length; var buf = new Buffer(1 + 4 + 4 + 6 + 1 + 4 + signalLen); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(6, 5, true); buf.write('signal', 9, 6, 'ascii'); buf[15] = 0; buf.writeUInt32BE(signalLen, 16, true); buf.write(signal, 20, signalLen, 'ascii'); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', signal)'); return send(this, buf); }
n/a
subsystem = function (chan, name, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var nameLen = Buffer.byteLength(name); var buf = new Buffer(1 + 4 + 4 + 9 + 1 + 4 + nameLen); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(9, 5, true); buf.write('subsystem', 9, 9, 'ascii'); buf[18] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(nameLen, 19, true); buf.write(name, 23, nameLen, 'ascii'); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', subsystem: ' + name + ')'); return send(this, buf); }
n/a
tcpipForward = function (bindAddr, bindPort, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); var addrlen = Buffer.byteLength(bindAddr); var buf = new Buffer(1 + 4 + 13 + 1 + 4 + addrlen + 4); buf[0] = MESSAGE.GLOBAL_REQUEST; buf.writeUInt32BE(13, 1, true); buf.write('tcpip-forward', 5, 13, 'ascii'); buf[18] = (wantReply === undefined || wantReply === true ? 1 : 0); buf.writeUInt32BE(addrlen, 19, true); buf.write(bindAddr, 23, addrlen, 'ascii'); buf.writeUInt32BE(bindPort, 23 + addrlen, true); this.debug('DEBUG: Outgoing: Writing GLOBAL_REQUEST (tcpip-forward)'); return send(this, buf); }
n/a
windowChange = function (chan, rows, cols, height, width) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var buf = new Buffer(1 + 4 + 4 + 13 + 1 + 4 + 4 + 4 + 4); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(13, 5, true); buf.write('window-change', 9, 13, 'ascii'); buf[22] = 0; buf.writeUInt32BE(cols, 23, true); buf.writeUInt32BE(rows, 27, true); buf.writeUInt32BE(width, 31, true); buf.writeUInt32BE(height, 35, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', window-change)'); return send(this, buf); }
n/a
x11 = function (chan, initWindow, maxPacket, cfg) { if (!this.server) throw new Error('Server-only method called in client mode'); var addrLen = Buffer.byteLength(cfg.originAddr); var p = 24 + addrLen; var buf = new Buffer(1 + 4 + 3 + 4 + 4 + 4 + 4 + addrLen + 4); buf[0] = MESSAGE.CHANNEL_OPEN; buf.writeUInt32BE(3, 1, true); buf.write('x11', 5, 3, 'ascii'); buf.writeUInt32BE(chan, 8, true); buf.writeUInt32BE(initWindow, 12, true); buf.writeUInt32BE(maxPacket, 16, true); buf.writeUInt32BE(addrLen, 20, true); buf.write(cfg.originAddr, 24, addrLen, 'ascii'); buf.writeUInt32BE(cfg.originPort, p, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_OPEN (' + chan + ', x11)'); return send(this, buf); }
n/a
x11Forward = function (chan, cfg, wantReply) { if (this.server) throw new Error('Client-only method called in server mode'); // Does not consume window space var protolen = Buffer.byteLength(cfg.protocol); var cookielen = Buffer.byteLength(cfg.cookie); var buf = new Buffer(1 + 4 + 4 + 7 + 1 + 1 + 4 + protolen + 4 + cookielen + 4); buf[0] = MESSAGE.CHANNEL_REQUEST; buf.writeUInt32BE(chan, 1, true); buf.writeUInt32BE(7, 5, true); buf.write('x11-req', 9, 7, 'ascii'); buf[16] = (wantReply === undefined || wantReply === true ? 1 : 0); buf[17] = (cfg.single ? 1 : 0); buf.writeUInt32BE(protolen, 18, true); var bp = 22; if (Buffer.isBuffer(cfg.protocol)) cfg.protocol.copy(buf, bp); else buf.write(cfg.protocol, bp, protolen, 'utf8'); bp += protolen; buf.writeUInt32BE(cookielen, bp, true); bp += 4; if (Buffer.isBuffer(cfg.cookie)) cfg.cookie.copy(buf, bp); else buf.write(cfg.cookie, bp, cookielen, 'utf8'); bp += cookielen; buf.writeUInt32BE((cfg.screen || 0), bp, true); this.debug('DEBUG: Outgoing: Writing CHANNEL_REQUEST (' + chan + ', x11-req)'); return send(this, buf); }
n/a
function BigInteger(a, b, c) { if(a != null) if("number" == typeof a) this.fromNumber(a,b,c); else if(b == null && "string" != typeof a) this.fromString(a,256); else this.fromString(a,b); }
n/a
function Barrett(m) { // setup Barrett this.r2 = nbi(); this.q3 = nbi(); BigInteger.ONE.dlShiftTo(2*m.t,this.r2); this.mu = this.r2.divide(m); this.m = m; }
n/a
function bnAbs() { return (this.s<0)?this.negate():this; }
...
r.t = i;
r.clamp();
}
// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo(a,r) {
var x = this.abs(), y = a.abs();
var i = x.t;
r.t = i+y.t;
while(--i >= 0) r[i] = 0;
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
r.s = 0;
r.clamp();
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
...
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
...
if(ac) c.subTo(a,c);
d.subTo(b,d);
}
}
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
if(d.compareTo(m) >= 0) return d.subtract(m);
if(d.signum() < 0) d.addTo(m,d); else return d;
if(d.signum() < 0) return d.add(m); else return d;
}
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,
151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,
337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,
541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,
743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,
971,977,983,991,997];
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
// (public) test primality with certainty >= 1-.5^t
function bnIsProbablePrime(t) {
...
function bnpAddTo(a, r) { var i = 0, c = 0, m = Math.min(a.t,this.t); while(i < m) { c += this[i]+a[i]; r[i++] = c&this.DM; c >>= this.DB; } if(a.t < this.t) { c += a.s; while(i < this.t) { c += this[i]; r[i++] = c&this.DM; c >>= this.DB; } c += this.s; } else { c += this.s; while(i < a.t) { c += a[i]; r[i++] = c&this.DM; c >>= this.DB; } c += a.s; } r.s = (c<0)?-1:0; if(c > 0) r[i++] = c; else if(c < -1) r[i++] = this.DV+c; r.t = i; r.clamp(); }
...
if(c > 0) r[i++] = c;
else if(c < -1) r[i++] = this.DV+c;
r.t = i;
r.clamp();
}
// (public) this + a
function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
// (public) this - a
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
// (public) this * a
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
...
function am3(i, x, w, j, c, n) { var xl = x&0x3fff, xh = x>>14; while(--n >= 0) { var l = this[i]&0x3fff; var h = this[i++]>>14; var m = xh*l+h*xl; l = xl*l+((m&0x3fff)<<14)+w[j]+c; c = (l>>28)+(m>>14)+xh*h; w[j++] = l&0xfffffff; } return c; }
...
// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo(a,r) {
var x = this.abs(), y = a.abs();
var i = x.t;
r.t = i+y.t;
while(--i >= 0) r[i] = 0;
for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
r.s = 0;
r.clamp();
if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
}
// (protected) r = this^2, r != this (HAC 14.16)
function bnpSquareTo(r) {
...
function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
n/a
function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
n/a
function bnBitCount() { var r = 0, x = this.s&this.DM; for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); return r; }
n/a
function bnBitLength() { if(this.t <= 0) return 0; return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); }
...
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
}
else {
// new BigInteger(int,RNG)
var x = new Array(), t = a&7;
x.length = (a>>3)+1;
...
function bnpBitwiseTo(a, op, r) { var i, f, m = Math.min(a.t,this.t); for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); if(a.t < this.t) { f = a.s&this.DM; for(i = m; i < this.t; ++i) r[i] = op(this[i],f); r.t = this.t; } else { f = this.s&this.DM; for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); r.t = a.t; } r.s = op(this.s,a.s); r.clamp(); }
...
function bnpFromNumber(a,b,c) {
if("number" == typeof b) {
// new BigInteger(int,int,RNG)
if(a < 2) this.fromInt(1);
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
}
...
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
n/a
function bnpChangeBit(n, op) { var r = BigInteger.ONE.shiftLeft(n); this.bitwiseTo(r,op,r); return r; }
...
function bnpChangeBit(n,op) {
var r = BigInteger.ONE.shiftLeft(n);
this.bitwiseTo(r,op,r);
return r;
}
// (public) this | (1<<n)
function bnSetBit(n) { return this.changeBit(n,op_or); }
// (public) this & ~(1<<n)
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
// (public) this ^ (1<<n)
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
...
function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
...
else return 1;
}
// (protected) convert to radix string
function bnpToRadix(b) {
if(b == null) b = 10;
if(this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b,cs);
var d = nbv(a), y = nbi(), z = nbi(), r = "";
this.divRemTo(d,y,z);
while(y.signum() > 0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
}
...
function bnpClamp() { var c = this.s&this.DM; while(this.t > 0 && this[this.t-1] == c) --this.t; }
...
sh += k;
if(sh >= this.DB) sh -= this.DB;
}
if(k == 8 && (s[0]&0x80) != 0) {
this.s = -1;
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
}
this.clamp();
if(mi) BigInteger.ZERO.subTo(this,this);
}
// (protected) clamp off excess high words
function bnpClamp() {
var c = this.s&this.DM;
while(this.t > 0 && this[this.t-1] == c) --this.t;
...
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
n/a
function bnClone() { var r = nbi(); this.copyTo(r); return r; }
...
}
}
return z.revert(r);
}
// (public) gcd(this,a) (HAC 14.54)
function bnGCD(a) {
var x = (this.s<0)?this.negate():this.clone();
var y = (a.s<0)?a.negate():a.clone();
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
if(g < 0) return x;
if(i < g) g = i;
if(g > 0) {
x.rShiftTo(g,x);
...
function bnCompareTo(a) { var r = this.s-a.s; if(r != 0) return r; var i = this.t; r = i-a.t; if(r != 0) return (this.s<0)?-r:r; while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; return 0; }
...
var ys = y.t;
var y0 = y[ys-1];
if(y0 == 0) return;
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
y.dlShiftTo(j,t);
if(r.compareTo(t) >= 0) {
r[r.t++] = 1;
r.subTo(t,r);
}
BigInteger.ONE.dlShiftTo(ys,t);
t.subTo(y,y); // "negative" y so we can replace sub with am later
while(y.t < ys) y[y.t++] = 0;
while(--j >= 0) {
...
function bnpCopyTo(r) { for(var i = this.t-1; i >= 0; --i) r[i] = this[i]; r.t = this.t; r.s = this.s; }
...
// r != q, this != m. q or r may be null.
function bnpDivRemTo(m,q,r) {
var pm = m.abs();
if(pm.t <= 0) return;
var pt = this.abs();
if(pt.t < pm.t) {
if(q != null) q.fromInt(0);
if(r != null) this.copyTo(r);
return;
}
if(r == null) r = nbi();
var y = nbi(), ts = this.s, ms = m.s;
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
else { pm.copyTo(y); pt.copyTo(r); }
...
function bnpDAddOffset(n, w) { if(n == 0) return; while(this.t <= w) this[this.t++] = 0; this[w] += n; while(this[w] >= this.DV) { this[w] -= this.DV; if(++w >= this.t) this[this.t++] = 0; ++this[w]; } }
...
if(x < 0) {
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
continue;
}
w = b*w+x;
if(++j >= cs) {
this.dMultiply(d);
this.dAddOffset(w,0);
j = 0;
w = 0;
}
}
if(j > 0) {
this.dMultiply(Math.pow(b,j));
this.dAddOffset(w,0);
...
function bnpDMultiply(n) { this[this.t] = this.am(0,n-1,this,0,0,this.t); ++this.t; this.clamp(); }
...
var x = intAt(s,i);
if(x < 0) {
if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
continue;
}
w = b*w+x;
if(++j >= cs) {
this.dMultiply(d);
this.dAddOffset(w,0);
j = 0;
w = 0;
}
}
if(j > 0) {
this.dMultiply(Math.pow(b,j));
...
function bnpDivRemTo(m, q, r) { var pm = m.abs(); if(pm.t <= 0) return; var pt = this.abs(); if(pt.t < pm.t) { if(q != null) q.fromInt(0); if(r != null) this.copyTo(r); return; } if(r == null) r = nbi(); var y = nbi(), ts = this.s, ms = m.s; var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } var ys = y.t; var y0 = y[ys-1]; if(y0 == 0) return; var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0); var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2; var i = r.t, j = i-ys, t = (q==null)?nbi():q; y.dlShiftTo(j,t); if(r.compareTo(t) >= 0) { r[r.t++] = 1; r.subTo(t,r); } BigInteger.ONE.dlShiftTo(ys,t); t.subTo(y,y); // "negative" y so we can replace sub with am later while(y.t < ys) y[y.t++] = 0; while(--j >= 0) { // Estimate quotient digit var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out y.dlShiftTo(j,t); r.subTo(t,r); while(r[i] < --qd) r.subTo(t,r); } } if(q != null) { r.drShiftTo(ys,q); if(ts != ms) BigInteger.ZERO.subTo(q,q); } r.t = ys; r.clamp(); if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder if(ts < 0) BigInteger.ZERO.subTo(r,r); }
...
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
if(ts < 0) BigInteger.ZERO.subTo(r,r);
}
// (public) this mod a
function bnMod(a) {
var r = nbi();
this.abs().divRemTo(a,null,r);
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
return r;
}
// Modular reduction using "classic" algorithm
function Classic(m) { this.m = m; }
function cConvert(x) {
...
function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
...
// Barrett modular reduction
function Barrett(m) {
// setup Barrett
this.r2 = nbi();
this.q3 = nbi();
BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
this.mu = this.r2.divide(m);
this.m = m;
}
function barrettConvert(x) {
if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
else if(x.compareTo(this.m) < 0) return x;
else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
...
function bnDivideAndRemainder(a) { var q = nbi(), r = nbi(); this.divRemTo(a,q,r); return new Array(q,r); }
n/a
function bnpDLShiftTo(n, r) { var i; for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; for(i = n-1; i >= 0; --i) r[i] = 0; r.t = this.t+n; r.s = this.s; }
...
else { pm.copyTo(y); pt.copyTo(r); }
var ys = y.t;
var y0 = y[ys-1];
if(y0 == 0) return;
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
y.dlShiftTo(j,t);
if(r.compareTo(t) >= 0) {
r[r.t++] = 1;
r.subTo(t,r);
}
BigInteger.ONE.dlShiftTo(ys,t);
t.subTo(y,y); // "negative" y so we can replace sub with am later
while(y.t < ys) y[y.t++] = 0;
...
function bnpDRShiftTo(n, r) { for(var i = n; i < this.t; ++i) r[i-n] = this[i]; r.t = Math.max(this.t-n,0); r.s = this.s; }
...
if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
y.dlShiftTo(j,t);
r.subTo(t,r);
while(r[i] < --qd) r.subTo(t,r);
}
}
if(q != null) {
r.drShiftTo(ys,q);
if(ts != ms) BigInteger.ZERO.subTo(q,q);
}
r.t = ys;
r.clamp();
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
if(ts < 0) BigInteger.ZERO.subTo(r,r);
}
...
function bnEquals(a) { return(this.compareTo(a)==0); }
n/a
function bnpExp(e, z) { if(e > 0xffffffff || e < 1) return BigInteger.ONE; var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; g.copyTo(r); while(--i >= 0) { z.sqrTo(r,r2); if((e&(1<<i)) > 0) z.mulTo(r2,g,r); else { var t = r; r = r2; r2 = t; } } return z.revert(r); }
...
return z.revert(r);
}
// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt(e,m) {
var z;
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
return this.exp(e,z);
}
// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
BigInteger.prototype.clamp = bnpClamp;
...
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
n/a
function bnpFromInt(x) { this.t = 1; this.s = (x<0)?-1:0; if(x > 0) this[0] = x; else if(x < -1) this[0] = x+this.DV; else this.t = 0; }
...
this.s = (x<0)?-1:0;
if(x > 0) this[0] = x;
else if(x < -1) this[0] = x+this.DV;
else this.t = 0;
}
// return bigint initialized to value
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
// (protected) set from string and radix
function bnpFromString(s,b) {
var k;
if(b == 16) k = 4;
else if(b == 8) k = 3;
else if(b == 256) k = 8; // byte array
...
function bnpFromNumber(a, b, c) { if("number" == typeof b) { // new BigInteger(int,int,RNG) if(a < 2) this.fromInt(1); else { this.fromNumber(a,c); if(!this.testBit(a-1)) // force MSB set this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); if(this.isEven()) this.dAddOffset(1,0); // force odd while(!this.isProbablePrime(b)) { this.dAddOffset(2,0); if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); } } } else { // new BigInteger(int,RNG) var x = new Array(), t = a&7; x.length = (a>>3)+1; b.nextBytes(x); if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0; this.fromString(x,256); } }
...
// JavaScript engine analysis
var canary = 0xdeadbeefcafe;
var j_lm = ((canary&0xffffff)==0xefcafe);
// (public) Constructor
function BigInteger(a,b,c) {
if(a != null)
if("number" == typeof a) this.fromNumber(a,b,c);
else if(b == null && "string" != typeof a) this.fromString(a,256);
else this.fromString(a,b);
}
// return new, unset BigInteger
function nbi() { return new BigInteger(null); }
...
function bnpFromRadix(s, b) { this.fromInt(0); if(b == null) b = 10; var cs = this.chunkSize(b); var d = Math.pow(b,cs), mi = false, j = 0, w = 0; for(var i = 0; i < s.length; ++i) { var x = intAt(s,i); if(x < 0) { if(s.charAt(i) == "-" && this.signum() == 0) mi = true; continue; } w = b*w+x; if(++j >= cs) { this.dMultiply(d); this.dAddOffset(w,0); j = 0; w = 0; } } if(j > 0) { this.dMultiply(Math.pow(b,j)); this.dAddOffset(w,0); } if(mi) BigInteger.ZERO.subTo(this,this); }
...
var k;
if(b == 16) k = 4;
else if(b == 8) k = 3;
else if(b == 256) k = 8; // byte array
else if(b == 2) k = 1;
else if(b == 32) k = 5;
else if(b == 4) k = 2;
else { this.fromRadix(s,b); return; }
this.t = 0;
this.s = 0;
var i = s.length, mi = false, sh = 0;
while(--i >= 0) {
var x = (k==8)?s[i]&0xff:intAt(s,i);
if(x < 0) {
if(s.charAt(i) == "-") mi = true;
...
function bnpFromString(s, b) { var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 256) k = 8; // byte array else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else { this.fromRadix(s,b); return; } this.t = 0; this.s = 0; var i = s.length, mi = false, sh = 0; while(--i >= 0) { var x = (k==8)?s[i]&0xff:intAt(s,i); if(x < 0) { if(s.charAt(i) == "-") mi = true; continue; } mi = false; if(sh == 0) this[this.t++] = x; else if(sh+k > this.DB) { this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh; this[this.t++] = (x>>(this.DB-sh)); } else this[this.t-1] |= x<<sh; sh += k; if(sh >= this.DB) sh -= this.DB; } if(k == 8 && (s[0]&0x80) != 0) { this.s = -1; if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh; } this.clamp(); if(mi) BigInteger.ZERO.subTo(this,this); }
...
var canary = 0xdeadbeefcafe;
var j_lm = ((canary&0xffffff)==0xefcafe);
// (public) Constructor
function BigInteger(a,b,c) {
if(a != null)
if("number" == typeof a) this.fromNumber(a,b,c);
else if(b == null && "string" != typeof a) this.fromString(a,
256);
else this.fromString(a,b);
}
// return new, unset BigInteger
function nbi() { return new BigInteger(null); }
// am: Compute w_j += (x*this_i), propagate carries,
...
function bnGCD(a) { var x = (this.s<0)?this.negate():this.clone(); var y = (a.s<0)?a.negate():a.clone(); if(x.compareTo(y) < 0) { var t = x; x = y; y = t; } var i = x.getLowestSetBit(), g = y.getLowestSetBit(); if(g < 0) return x; if(i < g) g = i; if(g > 0) { x.rShiftTo(g,x); y.rShiftTo(g,y); } while(x.signum() > 0) { if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); if(x.compareTo(y) >= 0) { x.subTo(y,x); x.rShiftTo(1,x); } else { y.subTo(x,y); y.rShiftTo(1,y); } } if(g > 0) y.lShiftTo(g,y); return y; }
n/a
function bnGetLowestSetBit() { for(var i = 0; i < this.t; ++i) if(this[i] != 0) return i*this.DB+lbit(this[i]); if(this.s < 0) return this.t*this.DB; return -1; }
...
}
// (public) gcd(this,a) (HAC 14.54)
function bnGCD(a) {
var x = (this.s<0)?this.negate():this.clone();
var y = (a.s<0)?a.negate():a.clone();
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
if(g < 0) return x;
if(i < g) g = i;
if(g > 0) {
x.rShiftTo(g,x);
y.rShiftTo(g,y);
}
while(x.signum() > 0) {
...
function bnIntValue() { if(this.s < 0) { if(this.t == 1) return this[0]-this.DV; else if(this.t == 0) return -1; } else if(this.t == 1) return this[0]; else if(this.t == 0) return 0; // assumes 16 < DB < 32 return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0]; }
...
if(b == null) b = 10;
if(this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b,cs);
var d = nbv(a), y = nbi(), z = nbi(), r = "";
this.divRemTo(d,y,z);
while(y.signum() > 0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
}
return z.intValue().toString(b) + r;
}
// (protected) convert from radix string
function bnpFromRadix(s,b) {
...
function bnpInvDigit() { if(this.t < 1) return 0; var x = this[0]; if((x&1) == 0) return 0; var y = x&3; // y == 1/x mod 2^2 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 // last step - calculate inverse mod DV directly; // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits // we really want the negative inverse, and -DV < y < DV return (y>0)?this.DV-y:-y; }
...
// we really want the negative inverse, and -DV < y < DV
return (y>0)?this.DV-y:-y;
}
// Montgomery reduction
function Montgomery(m) {
this.m = m;
this.mp = m.invDigit();
this.mpl = this.mp&0x7fff;
this.mph = this.mp>>15;
this.um = (1<<(m.DB-15))-1;
this.mt2 = 2*m.t;
}
// xR mod m
...
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
...
}
return z.revert(r);
}
// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt(e,m) {
var z;
if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
return this.exp(e,z);
}
// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
...
function bnIsProbablePrime(t) { var i, x = this.abs(); if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { for(i = 0; i < lowprimes.length; ++i) if(x[0] == lowprimes[i]) return true; return false; } if(x.isEven()) return false; i = 1; while(i < lowprimes.length) { var m = lowprimes[i], j = i+1; while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; m = x.modInt(m); while(i < j) if(m%lowprimes[i++] == 0) return false; } return x.millerRabin(t); }
...
// new BigInteger(int,int,RNG)
if(a < 2) this.fromInt(1);
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
}
else {
// new BigInteger(int,RNG)
...
function bnpLShiftTo(n, r) { var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<<cbs)-1; var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i; for(i = this.t-1; i >= 0; --i) { r[i+ds+1] = (this[i]>>cbs)|c; c = (this[i]&bm)<<bs; } for(i = ds-1; i >= 0; --i) r[i] = 0; r[ds] = c; r.t = this.t+ds+1; r.s = this.s; r.clamp(); }
...
if(q != null) q.fromInt(0);
if(r != null) this.copyTo(r);
return;
}
if(r == null) r = nbi();
var y = nbi(), ts = this.s, ms = m.s;
var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus
if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
else { pm.copyTo(y); pt.copyTo(r); }
var ys = y.t;
var y0 = y[ys-1];
if(y0 == 0) return;
var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
...
function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
...
r.t = this.t+n;
r.s = this.s;
}
// (protected) r = this >> n*DB
function bnpDRShiftTo(n,r) {
for(var i = n; i < this.t; ++i) r[i-n] = this[i];
r.t = Math.max(this.t-n,0);
r.s = this.s;
}
// (protected) r = this << n
function bnpLShiftTo(n,r) {
var bs = n%this.DB;
var cbs = this.DB-bs;
...
function bnpMillerRabin(t) { var n1 = this.subtract(BigInteger.ONE); var k = n1.getLowestSetBit(); if(k <= 0) return false; var r = n1.shiftRight(k); t = (t+1)>>1; if(t > lowprimes.length) t = lowprimes.length; var a = nbi(); for(var i = 0; i < t; ++i) { //Pick bases at random, instead of starting at 2 a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); var y = a.modPow(r,this); if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { var j = 1; while(j++ < k && y.compareTo(n1) != 0) { y = y.modPowInt(2,this); if(y.compareTo(BigInteger.ONE) == 0) return false; } if(y.compareTo(n1) != 0) return false; } } return true; }
...
i = 1;
while(i < lowprimes.length) {
var m = lowprimes[i], j = i+1;
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
m = x.modInt(m);
while(i < j) if(m%lowprimes[i++] == 0) return false;
}
return x.millerRabin(t);
}
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
function bnpMillerRabin(t) {
var n1 = this.subtract(BigInteger.ONE);
var k = n1.getLowestSetBit();
if(k <= 0) return false;
...
function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
...
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
r.t = this.t-ds;
r.clamp();
}
// (protected) r = this - a
function bnpSubTo(a,r) {
var i = 0, c = 0, m = Math.min(a.t,this.t);
while(i < m) {
c += this[i]-a[i];
r[i++] = c&this.DM;
c >>= this.DB;
}
if(a.t < this.t) {
c -= a.s;
...
function bnMod(a) { var r = nbi(); this.abs().divRemTo(a,null,r); if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); return r; }
...
if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
return r;
}
// Modular reduction using "classic" algorithm
function Classic(m) { this.m = m; }
function cConvert(x) {
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
else return x;
}
function cRevert(x) { return x; }
function cReduce(x) { x.divRemTo(this.m,null,x); }
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
...
function bnpModInt(n) { if(n <= 0) return 0; var d = this.DV%n, r = (this.s<0)?n-1:0; if(this.t > 0) if(d == 0) r = this[0]%n; else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; return r; }
...
return false;
}
if(x.isEven()) return false;
i = 1;
while(i < lowprimes.length) {
var m = lowprimes[i], j = i+1;
while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
m = x.modInt(m);
while(i < j) if(m%lowprimes[i++] == 0) return false;
}
return x.millerRabin(t);
}
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
function bnpMillerRabin(t) {
...
function bnModInverse(m) { var ac = m.isEven(); if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; var u = m.clone(), v = this.clone(); var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); while(u.signum() != 0) { while(u.isEven()) { u.rShiftTo(1,u); if(ac) { if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } a.rShiftTo(1,a); } else if(!b.isEven()) b.subTo(m,b); b.rShiftTo(1,b); } while(v.isEven()) { v.rShiftTo(1,v); if(ac) { if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } c.rShiftTo(1,c); } else if(!d.isEven()) d.subTo(m,d); d.rShiftTo(1,d); } if(u.compareTo(v) >= 0) { u.subTo(v,u); if(ac) a.subTo(c,a); b.subTo(d,b); } else { v.subTo(u,v); if(ac) c.subTo(a,c); d.subTo(b,d); } } if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; if(d.compareTo(m) >= 0) return d.subtract(m); if(d.signum() < 0) d.addTo(m,d); else return d; if(d.signum() < 0) return d.add(m); else return d; }
n/a
function bnModPow(e, m) { var i = e.bitLength(), k, r = nbv(1), z; if(i <= 0) return r; else if(i < 18) k = 1; else if(i < 48) k = 3; else if(i < 144) k = 4; else if(i < 768) k = 5; else k = 6; if(i < 8) z = new Classic(m); else if(m.isEven()) z = new Barrett(m); else z = new Montgomery(m); // precomputation var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1; g[1] = z.convert(this); if(k > 1) { var g2 = nbi(); z.sqrTo(g[1],g2); while(n <= km) { g[n] = nbi(); z.mulTo(g2,g[n-2],g[n]); n += 2; } } var j = e.t-1, w, is1 = true, r2 = nbi(), t; i = nbits(e[j])-1; while(j >= 0) { if(i >= k1) w = (e[j]>>(i-k1))&km; else { w = (e[j]&((1<<(i+1))-1))<<(k1-i); if(j > 0) w |= e[j-1]>>(this.DB+i-k1); } n = k; while((w&1) == 0) { w >>= 1; --n; } if((i -= n) < 0) { i += this.DB; --j; } if(is1) { // ret == 1, don't bother squaring or multiplying it g[w].copyTo(r); is1 = false; } else { while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } z.mulTo(r2,g[w],r); } while(j >= 0 && (e[j]&(1<<i)) == 0) { z.sqrTo(r,r2); t = r; r = r2; r2 = t; if(--i < 0) { i = this.DB-1; --j; } } } return z.revert(r); }
...
var r = n1.shiftRight(k);
t = (t+1)>>1;
if(t > lowprimes.length) t = lowprimes.length;
var a = nbi();
for(var i = 0; i < t; ++i) {
//Pick bases at random, instead of starting at 2
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
var y = a.modPow(r,this);
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
var j = 1;
while(j++ < k && y.compareTo(n1) != 0) {
y = y.modPowInt(2,this);
if(y.compareTo(BigInteger.ONE) == 0) return false;
}
if(y.compareTo(n1) != 0) return false;
...
function bnModPowInt(e, m) { var z; if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); return this.exp(e,z); }
...
for(var i = 0; i < t; ++i) {
//Pick bases at random, instead of starting at 2
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
var y = a.modPow(r,this);
if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
var j = 1;
while(j++ < k && y.compareTo(n1) != 0) {
y = y.modPowInt(2,this);
if(y.compareTo(BigInteger.ONE) == 0) return false;
}
if(y.compareTo(n1) != 0) return false;
}
}
return true;
}
...
function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
n/a
function bnpMultiplyLowerTo(a, n, r) { var i = Math.min(this.t+a.t,n); r.s = 0; // assumes a,this >= 0 r.t = i; while(i > 0) r[--i] = 0; var j; for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); r.clamp(); }
...
function barrettRevert(x) { return x; }
// x = x mod m (HAC 14.42)
function barrettReduce(x) {
x.drShiftTo(this.m.t-1,this.r2);
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
x.subTo(this.r2,x);
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
}
// r = x^2 mod m; x != r
function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
...
function bnpMultiplyTo(a, r) { var x = this.abs(), y = a.abs(); var i = x.t; r.t = i+y.t; while(--i >= 0) r[i] = 0; for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); r.s = 0; r.clamp(); if(this.s != a.s) BigInteger.ZERO.subTo(r,r); }
...
function Classic(m) { this.m = m; }
function cConvert(x) {
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
else return x;
}
function cRevert(x) { return x; }
function cReduce(x) { x.divRemTo(this.m,null,x); }
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
Classic.prototype.convert = cConvert;
Classic.prototype.revert = cRevert;
Classic.prototype.reduce = cReduce;
Classic.prototype.mulTo = cMulTo;
Classic.prototype.sqrTo = cSqrTo;
...
function bnpMultiplyUpperTo(a, n, r) { --n; var i = r.t = this.t+a.t-n; r.s = 0; // assumes a,this >= 0 while(--i >= 0) r[i] = 0; for(i = Math.max(n-this.t,0); i < a.t; ++i) r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); r.clamp(); r.drShiftTo(1,r); }
...
function barrettRevert(x) { return x; }
// x = x mod m (HAC 14.42)
function barrettReduce(x) {
x.drShiftTo(this.m.t-1,this.r2);
if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
x.subTo(this.r2,x);
while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
}
// r = x^2 mod m; x != r
...
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
...
function bnpClamp() {
var c = this.s&this.DM;
while(this.t > 0 && this[this.t-1] == c) --this.t;
}
// (public) return string representation in given radix
function bnToString(b) {
if(this.s < 0) return "-"+this.negate().toString(b);
var k;
if(b == 16) k = 4;
else if(b == 8) k = 3;
else if(b == 2) k = 1;
else if(b == 32) k = 5;
else if(b == 4) k = 2;
else return this.toRadix(b);
...
function bnNot() { var r = nbi(); for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; r.t = this.t; r.s = ~this.s; return r; }
n/a
function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
n/a
function bnPow(e) { return this.exp(e,new NullExp()); }
...
dbits = 28;
BigInteger.prototype.DB = dbits;
BigInteger.prototype.DM = ((1<<dbits)-1);
BigInteger.prototype.DV = (1<<dbits);
var BI_FP = 52;
BigInteger.prototype.FV = Math.pow(2,BI_FP);
BigInteger.prototype.F1 = BI_FP-dbits;
BigInteger.prototype.F2 = 2*dbits-BI_FP;
// Digit conversions
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
var BI_RC = new Array();
var rr,vv;
...
function bnpRShiftTo(n, r) { r.s = this.s; var ds = Math.floor(n/this.DB); if(ds >= this.t) { r.t = 0; return; } var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<<bs)-1; r[0] = this[ds]>>bs; for(var i = ds+1; i < this.t; ++i) { r[i-ds-1] |= (this[i]&bm)<<cbs; r[i-ds] = this[i]>>bs; } if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs; r.t = this.t-ds; r.clamp(); }
...
}
if(q != null) {
r.drShiftTo(ys,q);
if(ts != ms) BigInteger.ZERO.subTo(q,q);
}
r.t = ys;
r.clamp();
if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
if(ts < 0) BigInteger.ZERO.subTo(r,r);
}
// (public) this mod a
function bnMod(a) {
var r = nbi();
this.abs().divRemTo(a,null,r);
...
function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
n/a
function bnSetBit(n) { return this.changeBit(n,op_or); }
n/a
function bnShiftLeft(n) { var r = nbi(); if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); return r; }
...
function bnpFromNumber(a,b,c) {
if("number" == typeof b) {
// new BigInteger(int,int,RNG)
if(a < 2) this.fromInt(1);
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
}
...
function bnShiftRight(n) { var r = nbi(); if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); return r; }
...
}
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
function bnpMillerRabin(t) {
var n1 = this.subtract(BigInteger.ONE);
var k = n1.getLowestSetBit();
if(k <= 0) return false;
var r = n1.shiftRight(k);
t = (t+1)>>1;
if(t > lowprimes.length) t = lowprimes.length;
var a = nbi();
for(var i = 0; i < t; ++i) {
//Pick bases at random, instead of starting at 2
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
var y = a.modPow(r,this);
...
function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
n/a
function bnSigNum() { if(this.s < 0) return -1; else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; else return 1; }
...
else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
else return 1;
}
// (protected) convert to radix string
function bnpToRadix(b) {
if(b == null) b = 10;
if(this.signum() == 0 || b < 2 || b > 36) return "0";
var cs = this.chunkSize(b);
var a = Math.pow(b,cs);
var d = nbv(a), y = nbi(), z = nbi(), r = "";
this.divRemTo(d,y,z);
while(y.signum() > 0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
...
function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
n/a
function bnpSquareTo(r) { var x = this.abs(); var i = r.t = 2*x.t; while(--i >= 0) r[i] = 0; for(i = 0; i < x.t-1; ++i) { var c = x.am(i,x[i],r,2*i,0,1); if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { r[i+x.t] -= x.DV; r[i+x.t+1] = 1; } } if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); r.s = 0; r.clamp(); }
...
function cConvert(x) {
if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
else return x;
}
function cRevert(x) { return x; }
function cReduce(x) { x.divRemTo(this.m,null,x); }
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
Classic.prototype.convert = cConvert;
Classic.prototype.revert = cRevert;
Classic.prototype.reduce = cReduce;
Classic.prototype.mulTo = cMulTo;
Classic.prototype.sqrTo = cSqrTo;
...
function bnpSubTo(a, r) { var i = 0, c = 0, m = Math.min(a.t,this.t); while(i < m) { c += this[i]-a[i]; r[i++] = c&this.DM; c >>= this.DB; } if(a.t < this.t) { c -= a.s; while(i < this.t) { c += this[i]; r[i++] = c&this.DM; c >>= this.DB; } c += this.s; } else { c += this.s; while(i < a.t) { c -= a[i]; r[i++] = c&this.DM; c >>= this.DB; } c -= a.s; } r.s = (c<0)?-1:0; if(c < -1) r[i++] = this.DV+c; else if(c > 0) r[i++] = c; r.t = i; r.clamp(); }
...
if(sh >= this.DB) sh -= this.DB;
}
if(k == 8 && (s[0]&0x80) != 0) {
this.s = -1;
if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
}
this.clamp();
if(mi) BigInteger.ZERO.subTo(this,this);
}
// (protected) clamp off excess high words
function bnpClamp() {
var c = this.s&this.DM;
while(this.t > 0 && this[this.t-1] == c) --this.t;
}
...
function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
...
else {
v.subTo(u,v);
if(ac) c.subTo(a,c);
d.subTo(b,d);
}
}
if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
if(d.compareTo(m) >= 0) return d.subtract(m);
if(d.signum() < 0) d.addTo(m,d); else return d;
if(d.signum() < 0) return d.add(m); else return d;
}
var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,
151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,
337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,
541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,
743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,
971,977,983,991,997];
var lplim = (1<<26)/lowprimes[lowprimes.length-1];
...
function bnTestBit(n) { var j = Math.floor(n/this.DB); if(j >= this.t) return(this.s!=0); return((this[j]&(1<<(n%this.DB)))!=0); }
...
// (protected) alternate constructor
function bnpFromNumber(a,b,c) {
if("number" == typeof b) {
// new BigInteger(int,int,RNG)
if(a < 2) this.fromInt(1);
else {
this.fromNumber(a,c);
if(!this.testBit(a-1)) // force MSB set
this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
if(this.isEven()) this.dAddOffset(1,0); // force odd
while(!this.isProbablePrime(b)) {
this.dAddOffset(2,0);
if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
}
}
...
function bnToByteArray() { var i = this.t, r = new Array(); r[0] = this.s; var p = this.DB-(i*this.DB)%8, d, k = 0; if(i-- > 0) { if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) r[k++] = d|(this.s<<(this.DB-p)); while(i >= 0) { if(p < 8) { d = (this[i]&((1<<p)-1))<<(8-p); d |= this[--i]>>(p+=this.DB-8); } else { d = (this[i]>>(p-=8))&0xff; if(p <= 0) { p += this.DB; --i; } } if((d&0x80) != 0) d |= -256; if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; if(k > 0 || d != this.s) r[k++] = d; } } return r; }
n/a
function bnpToRadix(b) { if(b == null) b = 10; if(this.signum() == 0 || b < 2 || b > 36) return "0"; var cs = this.chunkSize(b); var a = Math.pow(b,cs); var d = nbv(a), y = nbi(), z = nbi(), r = ""; this.divRemTo(d,y,z); while(y.signum() > 0) { r = (a+z.intValue()).toString(b).substr(1) + r; y.divRemTo(d,y,z); } return z.intValue().toString(b) + r; }
...
if(this.s < 0) return "-"+this.negate().toString(b);
var k;
if(b == 16) k = 4;
else if(b == 8) k = 3;
else if(b == 2) k = 1;
else if(b == 32) k = 5;
else if(b == 4) k = 2;
else return this.toRadix(b);
var km = (1<<k)-1, d, m = false, r = "", i = this.t;
var p = this.DB-(i*this.DB)%k;
if(i-- > 0) {
if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
while(i >= 0) {
if(p < k) {
d = (this[i]&((1<<p)-1))<<(k-p);
...
function bnToString(b) { if(this.s < 0) return "-"+this.negate().toString(b); var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else return this.toRadix(b); var km = (1<<k)-1, d, m = false, r = "", i = this.t; var p = this.DB-(i*this.DB)%k; if(i-- > 0) { if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } while(i >= 0) { if(p < k) { d = (this[i]&((1<<p)-1))<<(k-p); d |= this[--i]>>(p+=this.DB-k); } else { d = (this[i]>>(p-=k))&km; if(p <= 0) { p += this.DB; --i; } } if(d > 0) m = true; if(m) r += int2char(d); } } return m?r:"0"; }
...
function bnpClamp() {
var c = this.s&this.DM;
while(this.t > 0 && this[this.t-1] == c) --this.t;
}
// (public) return string representation in given radix
function bnToString(b) {
if(this.s < 0) return "-"+this.negate().toString(b);
var k;
if(b == 16) k = 4;
else if(b == 8) k = 3;
else if(b == 2) k = 1;
else if(b == 32) k = 5;
else if(b == 4) k = 2;
else return this.toRadix(b);
...
function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
n/a
function DSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var p = readString(key, key._pos, self, callback); if (p === false) return false; var q = readString(key, key._pos, self, callback); if (q === false) return false; var g = readString(key, key._pos, self, callback); if (g === false) return false; var y = readString(key, key._pos, self, callback); if (y === false) return false; var asnWriter = new Ber.Writer(); asnWriter.startSequence(); // algorithm asnWriter.startSequence(); asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa // algorithm parameters asnWriter.startSequence(); asnWriter.writeBuffer(p, Ber.Integer); asnWriter.writeBuffer(q, Ber.Integer); asnWriter.writeBuffer(g, Ber.Integer); asnWriter.endSequence(); asnWriter.endSequence(); // subjectPublicKey asnWriter.startSequence(Ber.BitString); asnWriter.writeByte(0x00); asnWriter.writeBuffer(y, Ber.Integer); asnWriter.endSequence(); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function DSASigBERToBare(signature) { if (signature.length <= 40) return signature; // This is a quick and dirty way to get from BER encoded r and s that // OpenSSL gives us, to just the bare values back to back (40 bytes // total) like OpenSSH (and possibly others) are expecting var asnReader = new Ber.Reader(signature); asnReader.readSequence(); var r = asnReader.readString(Ber.Integer, true); var s = asnReader.readString(Ber.Integer, true); var rOffset = 0; var sOffset = 0; if (r.length < 20) { var rNew = new Buffer(20); r.copy(rNew, 1); r = rNew; r[0] = 0; } if (s.length < 20) { var sNew = new Buffer(20); s.copy(sNew, 1); s = sNew; s[0] = 0; } if (r.length > 20 && r[0] === 0x00) rOffset = 1; if (s.length > 20 && s[0] === 0x00) sOffset = 1; var newSig = new Buffer((r.length - rOffset) + (s.length - sOffset)); r.copy(newSig, 0, rOffset); s.copy(newSig, r.length - rOffset, sOffset); return newSig; }
n/a
function DSASigBareToBER(signature) { if (signature.length > 40) return signature; // Change bare signature r and s values to ASN.1 BER values for OpenSSL var asnWriter = new Ber.Writer(); asnWriter.startSequence(); var r = signature.slice(0, 20); var s = signature.slice(20); if (r[0] & 0x80) { var rNew = new Buffer(21); rNew[0] = 0x00; r.copy(rNew, 1); r = rNew; } else if (r[0] === 0x00 && !(r[1] & 0x80)) { r = r.slice(1); } if (s[0] & 0x80) { var sNew = new Buffer(21); sNew[0] = 0x00; s.copy(sNew, 1); s = sNew; } else if (s[0] === 0x00 && !(s[1] & 0x80)) { s = s.slice(1); } asnWriter.writeBuffer(r, Ber.Integer); asnWriter.writeBuffer(s, Ber.Integer); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function ECDSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var curve = readString(key, key._pos, self, callback); if (curve === false) return false; var Q = readString(key, key._pos, self, callback); if (Q === false) return false; var ecCurveOID; switch (curve.toString('ascii')) { case 'nistp256': // prime256v1/secp256r1 ecCurveOID = '1.2.840.10045.3.1.7'; break; case 'nistp384': // secp384r1 ecCurveOID = '1.3.132.0.34'; break; case 'nistp521': // secp521r1 ecCurveOID = '1.3.132.0.35'; break; default: return false; } var asnWriter = new Ber.Writer(); asnWriter.startSequence(); // algorithm asnWriter.startSequence(); asnWriter.writeOID('1.2.840.10045.2.1'); // id-ecPublicKey // algorithm parameters (namedCurve) asnWriter.writeOID(ecCurveOID); asnWriter.endSequence(); // subjectPublicKey asnWriter.startSequence(Ber.BitString); asnWriter.writeByte(0x00); // XXX: hack to write a raw buffer without a tag -- yuck asnWriter._ensure(Q.length); Q.copy(asnWriter._buf, asnWriter._offset, 0, Q.length); asnWriter._offset += Q.length; // end hack asnWriter.endSequence(); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function ECDSASigASN1ToSSH(signature) { if (signature[0] === 0x00) return signature; // Convert SSH signature parameters to ASN.1 BER values for OpenSSL var asnReader = new Ber.Reader(signature); asnReader.readSequence(); var r = asnReader.readString(Ber.Integer, true); var s = asnReader.readString(Ber.Integer, true); if (r === null || s === null) throw new Error('Invalid signature'); var newSig = new Buffer(4 + r.length + 4 + s.length); newSig.writeUInt32BE(r.length, 0, true); r.copy(newSig, 4); newSig.writeUInt32BE(s.length, 4 + r.length, true); s.copy(newSig, 4 + 4 + r.length); return newSig; }
n/a
function ECDSASigSSHToASN1(signature, self, callback) { // Convert SSH signature parameters to ASN.1 BER values for OpenSSL var r = readString(signature, 0, self, callback); if (r === false) return false; var s = readString(signature, signature._pos, self, callback); if (s === false) return false; var asnWriter = new Ber.Writer(); asnWriter.startSequence(); asnWriter.writeBuffer(r, Ber.Integer); asnWriter.writeBuffer(s, Ber.Integer); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function RSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var e = readString(key, key._pos, self, callback); if (e === false) return false; var n = readString(key, key._pos, self, callback); if (n === false) return false; 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 asnWriter.buffer; }
n/a
function convertPPKPrivate(keyInfo) { if (!keyInfo.ppk || !keyInfo.public || !keyInfo.private) throw new Error("Key isn't a PPK"); else if (keyInfo._converted) return false; var pub = keyInfo.public; var priv = keyInfo.private; var asnWriter = new Ber.Writer(); var p; var q; if (keyInfo.type === 'rsa') { var e = readString(pub, 4 + 7); var n = readString(pub, pub._pos); var d = readString(priv, 0); p = readString(priv, priv._pos); q = readString(priv, priv._pos); var iqmp = readString(priv, priv._pos); var p1 = new BigInteger(p, 256); var q1 = new BigInteger(q, 256); var dmp1 = new BigInteger(d, 256); var dmq1 = new BigInteger(d, 256); dmp1 = new Buffer(dmp1.mod(p1.subtract(BigInteger.ONE)).toByteArray()); dmq1 = new Buffer(dmq1.mod(q1.subtract(BigInteger.ONE)).toByteArray()); 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(); } else { p = readString(pub, 4 + 7); q = readString(pub, pub._pos); var g = readString(pub, pub._pos); var y = readString(pub, pub._pos); var x = readString(priv, 0); asnWriter.startSequence(); asnWriter.writeInt(0x00, Ber.Integer); asnWriter.writeBuffer(p, Ber.Integer); asnWriter.writeBuffer(q, Ber.Integer); asnWriter.writeBuffer(g, Ber.Integer); asnWriter.writeBuffer(y, Ber.Integer); asnWriter.writeBuffer(x, Ber.Integer); asnWriter.endSequence(); } var b64key = asnWriter.buffer.toString('base64').replace(RE_KEY_LEN, '$1\n'); var fullkey = '-----BEGIN ' + (keyInfo.type === 'rsa' ? 'RSA' : 'DSA') + ' PRIVATE KEY-----\n' + b64key + (b64key[b64key.length - 1] === '\n' ? '' : '\n') + '-----END ' + (keyInfo.type === 'rsa' ? 'RSA' : 'DSA') + ' PRIVATE KEY-----'; keyInfo.private = asnWriter.buffer; keyInfo.privateOrig = new Buffer(fullkey); keyInfo._converted = true; return true; }
...
ret.publicOrig = pubkey.publicOrig;
ret.private = privateKey;
// automatically convert private key data to OpenSSL format (including PEM)
// if we don't need to wait for decryption
if (!ret.encryption)
utils.convertPPKPrivate(ret);
} else
return new Error('Unsupported key format');
return ret;
};
...
function decryptKey(keyInfo, passphrase) { if (keyInfo._decrypted || !keyInfo.encryption) return; var keylen = 0; var key; var iv; var dc; keyInfo.encryption = (SSH_TO_OPENSSL[keyInfo.encryption] || keyInfo.encryption); switch (keyInfo.encryption) { case 'aes-256-cbc': case 'aes-256-ctr': keylen = 32; break; case 'des-ede3-cbc': case 'des-ede3': case 'aes-192-cbc': case 'aes-192-ctr': keylen = 24; break; case 'aes-128-cbc': case 'aes-128-ctr': case 'cast-cbc': case 'bf-cbc': keylen = 16; break; default: throw new Error('Unsupported cipher for encrypted key: ' + keyInfo.encryption); } if (keyInfo.ppk) { iv = PPK_IV; key = Buffer.concat([ crypto.createHash('sha1') .update('\x00\x00\x00\x00' + passphrase, 'utf8') .digest(), crypto.createHash('sha1') .update('\x00\x00\x00\x01' + passphrase, 'utf8') .digest() ]); key = key.slice(0, keylen); } else { iv = new Buffer(keyInfo.extra[0], 'hex'); key = crypto.createHash('md5') .update(passphrase, 'utf8') .update(iv.slice(0, 8)) .digest(); while (keylen > key.length) { key = Buffer.concat([ key, (crypto.createHash('md5') .update(key) .update(passphrase, 'utf8') .update(iv) .digest()).slice(0, 8) ]); } if (key.length > keylen) key = key.slice(0, keylen); } dc = crypto.createDecipheriv(keyInfo.encryption, key, iv); dc.setAutoPadding(false); keyInfo.private = Buffer.concat([ dc.update(keyInfo.private), dc.final() ]); keyInfo._decrypted = true; if (keyInfo.privateOrig) { // Update our original base64-encoded version of the private key var orig = keyInfo.privateOrig.toString('utf8'); var newOrig = /^(.+(?:\r\n|\n))/.exec(orig)[1]; var b64key = keyInfo.private.toString('base64'); newOrig += b64key.match(/.{1,70}/g).join('\n'); newOrig += /((?:\r\n|\n).+)$/.exec(orig)[1]; keyInfo.privateOrig = newOrig; } else if (keyInfo.ppk) { var valid = verifyPPKMAC(keyInfo, passphrase, keyInfo.private); if (!valid) throw new Error('PPK MAC mismatch'); // Automatically convert private key data to OpenSSL format // (including PEM) convertPPKPrivate(keyInfo); } // Fill in full key type // TODO: make DRY, we do this also in keyParser if (keyInfo.type !== 'ec') { keyInfo.fulltype = 'ssh-' + keyInfo.type; } else { // ECDSA var asnReader = new Ber.Reader(keyInfo.private); asnReader.readSequence(); asnReader.readInt(); asnReader.readString(Ber.OctetString, true); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Skip context length if (offset !== null) { asnReader._offset = offset; switch (asnReader.readOID()) { case '1.2.840.10045.3.1.7': // prime256v1/secp256r1 keyInfo.fulltype = 'ecdsa-sha2-nistp256'; break; case '1.3.132.0.34': // secp384r1 keyInfo.fulltype = 'ecdsa-sha2-nistp384'; break; case '1.3.132.0.35': // secp521r1 keyInfo.fulltype = 'ecdsa-sha2-nistp521'; break; } } if (keyInfo.fulltype === undefined) return new Error('Unsupported EC private key type'); } }
n/a
function genPublicKey(keyInfo) { var publicKey; var i; // RSA var n; var e; // DSA var p; var q; var g; var y; // ECDSA var d; var Q; var ecCurveOID; var ecCurveName; if (keyInfo.private) { // parsing private key in ASN.1 format in order to generate a public key var privKey = keyInfo.private; var asnReader = new Ber.Reader(privKey); var errMsg; if (asnReader.readSequence() === null) { errMsg = 'Malformed private key (expected sequence)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // version (ignored) if (asnReader.readInt() === null) { errMsg = 'Malformed private key (expected version)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } if (keyInfo.type === 'rsa') { // modulus (n) -- integer n = asnReader.readString(Ber.Integer, true); if (n === null) { errMsg = 'Malformed private key (expected RSA n value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // public exponent (e) -- integer e = asnReader.readString(Ber.Integer, true); if (e === null) { errMsg = 'Malformed private key (expected RSA e value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } publicKey = new Buffer(4 + 7 // ssh-rsa + 4 + n.length + 4 + e.length); publicKey.writeUInt32BE(7, 0, true); publicKey.write('ssh-rsa', 4, 7, 'ascii'); i = 4 + 7; publicKey.writeUInt32BE(e.length, i, true); e.copy(publicKey, i += 4); publicKey.writeUInt32BE(n.length, i += e.length, true); n.copy(publicKey, i += 4); } else if (keyInfo.type === 'dss') { // DSA // prime (p) -- integer p = asnReader.readString(Ber.Integer, true); if (p === null) { errMsg = 'Malformed private key (expected DSA p value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // group order (q) -- integer q = asnReader.readString(Ber.Integer, true); if (q === null) { errMsg = 'Malformed private key (expected DSA q value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // group generator (g) -- integer g = asnReader.readString(Ber.Integer, true); if (g === null) { errMsg = 'Malformed private key (expected DSA g value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // public key value (y) -- integer y = asnReader.readString(Ber.Integer, true); if (y === null) { errMsg = 'Malformed private key (expected DSA y value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } publicKey = new Buffer(4 + 7 // ssh-dss + 4 + p.length + 4 + q.length + 4 + g.length + 4 + y.length); publicKey.writeUInt32BE(7, 0, true); publicKey.write('ssh-dss', 4, 7, 'ascii'); i = 4 + 7; publicKey.writeUInt32BE(p.length, i, true); p.copy(publicKey, i += 4); publicKey.writeUInt32BE(q.length, i += p.length, true); q.copy(publicKey, i += 4); publicKey.writeUInt32BE(g.length, i += q.length, true); g.copy(publicKey, i += 4); publicKey.writeUInt32BE(y.length, i += g.length, true); y.copy(publicKey, i += 4); } else { // ECDSA d = asnReader.readString(Ber.OctetString, true); if (d === null) throw new Error('Malformed private key (expected ECDSA private key)'); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Sk ...
...
if (!ret.encryption) {
var valid = utils.verifyPPKMAC(ret, undefined, privateKey);
if (!valid)
throw new Error('PPK MAC mismatch');
}
// generate a PEM encoded version of the public key
var pubkey = utils.genPublicKey(ret);
ret.public = pubkey.public;
ret.publicOrig = pubkey.publicOrig;
ret.private = privateKey;
// automatically convert private key data to OpenSSL format (including PEM)
// if we don't need to wait for decryption
...
function isStreamCipher(name) { return RE_STREAM.test(name); }
n/a
function iv_inc(iv) { var n = 12; var c = 0; do { --n; c = iv[n]; if (c === 255) iv[n] = 0; else { iv[n] = ++c; return; } } while (n > 4); }
n/a
parseKey = function (data) { if (Buffer.isBuffer(data)) data = data.toString('utf8'); else if (typeof data !== 'string') return new Error('Key data must be a Buffer or string'); var ret = { fulltype: undefined, type: undefined, curve: undefined, extra: undefined, comment: undefined, encryption: undefined, private: undefined, privateOrig: undefined, public: undefined, publicOrig: undefined }; var m; var i; var len; data = data.trim().split(/\r\n|\n/); while (!data[0].length) data.shift(); while (!data.slice(-1)[0].length) data.pop(); var orig = data.join('\n'); if ((m = RE_HEADER_OPENSSH_PRIV.exec(data[0])) && RE_FOOTER_OPENSSH_PRIV.test(data.slice(-1))) { // OpenSSH private key var keyType = m[1].toLowerCase(); if (keyType === 'dsa') keyType = 'dss'; if (keyType === 'ec' && semver.lt(process.version, '5.2.0')) { return new Error( 'EC private keys are not supported in this version of node' ); } if (!RE_HEADER_OPENSSH.test(data[1])) { // unencrypted, no headers var privData = new Buffer(data.slice(1, -1).join(''), 'base64'); if (keyType !== 'ec') { ret.fulltype = 'ssh-' + keyType; } else { // ECDSA var asnReader = new Ber.Reader(privData); asnReader.readSequence(); asnReader.readInt(); asnReader.readString(Ber.OctetString, true); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Skip context length if (offset !== null) { asnReader._offset = offset; switch (asnReader.readOID()) { case '1.2.840.10045.3.1.7': // prime256v1/secp256r1 ret.fulltype = 'ecdsa-sha2-nistp256'; break; case '1.3.132.0.34': // secp384r1 ret.fulltype = 'ecdsa-sha2-nistp384'; break; case '1.3.132.0.35': // secp521r1 ret.fulltype = 'ecdsa-sha2-nistp521'; break; } } if (ret.fulltype === undefined) return new Error('Unsupported EC private key type'); } ret.private = privData; } else { // possibly encrypted, headers for (i = 1, len = data.length; i < len; ++i) { m = RE_HEADER_OPENSSH.exec(data[i]); if (m) { m[1] = m[1].toLowerCase(); if (m[1] === 'dek-info') { m[2] = m[2].split(','); ret.encryption = m[2][0].toLowerCase(); if (m[2].length > 1) ret.extra = m[2].slice(1); } } else if (data[i].length) break; } ret.private = new Buffer(data.slice(i, -1).join(''), 'base64'); } ret.type = keyType; ret.privateOrig = new Buffer(orig); } else if (m = RE_HEADER_OPENSSH_PUB.exec(data[0])) { // OpenSSH public key ret.fulltype = m[1]; ret.type = (m[2] || 'ec').toLowerCase(); ret.public = new Buffer(m[4], 'base64'); ret.publicOrig = new Buffer(orig); ret.comment = m[5]; if (m[3]) // ECDSA only ret.curve = 'nistp' + m[3]; } else if (RE_HEADER_RFC4716_PUB.test(data[0]) && RE_FOOTER_RFC4716_PUB.test(data.slice(-1))) { if (data[1].indexOf(': ') === -1) { // no headers ret.public = new Buffer(data.slice(1, -1).join(''), 'base64'); } else { // headers for (i = 1, len = data.length; i < len; ++i) { if (data[i].indexOf(': ') === -1) { if (data[i].length) break; // start of key data else continue; // empty line } while (data[i].substr(-1) === '\\') { if (i + 1 < len) { data[i] = data[i].slice(0, -1) + data[i + 1]; data.splice(i + 1, 1); --len; } else return new Error('RFC4716 public key missing header continuation line'); } m = RE_HEADER_RFC4716.exec(data[i]); if (m) { m[1] = m[1].toLo ...
...
* **tcpipForward**(< _string_ >bindAddr, < _integer_ >bindPort[, < _boolean_ >wantReply]) - _boolean_
- Writes a tcpip forward global request packet. `wantReply` defaults to `true`. Returns `false` if you should wait for the `continue
` event before sending any more traffic.
* **cancelTcpipForward**(< _string_ >bindAddr, < _integer_ >bindPort[, < _boolean_ >wantReply]) -
_boolean_ - Writes a cancel tcpip forward global request packet. `wantReply` defaults to `true`. Returns `false` if you should wait
for the `continue` event before sending any more traffic.
* **authPassword**(< _string_ >username, < _string_ >password) - _boolean_ - Writes a password userauth request
packet. Returns `false` if you should wait for the `continue` event before sending any more traffic.
* **authPK**(< _string_ >username, < _object_ >pubKey[, < _function_ >cbSign]) - _boolean_ - Writes
a publickey userauth request packet. `pubKey` is the object returned from using `utils.parseKey
()` on a private or public key. If `cbSign` is not present, a pubkey check userauth packet is written. Otherwise `cbSign`
is called with `(blob, callback)`, where `blob` is the data to sign with the private key and the resulting signature _Buffer_ is
passed to `callback` as the first argument. Returns `false` if you should wait for the `continue` event before sending any more
traffic.
* **authHostbased**(< _string_ >username, < _object_ >pubKey, < _string_ >localHostname, < _string_
>localUsername, < _function_ >cbSign) - _boolean_ - Writes a hostbased userauth request packet. `pubKey` is the
object returned from using `utils.parseKey()` on a private or public key. `cbSign` is called with `(blob, callback)`, where `blob
` is the data to sign with the private key and the resulting signature _Buffer_ is passed to `callback` as the first argument. Returns
`false` if you should wait for the `continue` event before sending any more traffic.
* **authKeyboard**(< _string_ >username) - _boolean_ - Writes a keyboard-interactive userauth request packet. Returns `
false` if you should wait for the `continue` event before sending any more traffic.
* **authNone**(< _string_ >username) - _boolean_ - Writes a "none" userauth request packet. Returns `false`
if you should wait for the `continue` event before sending any more traffic.
...
function readInt(buffer, start, stream, cb) { var bufferLen = buffer.length; if (start < 0 || start >= bufferLen || (bufferLen - start) < 4) { stream && stream._cleanup(cb); return false; } return buffer.readUInt32BE(start, true); }
...
var privData = new Buffer(data.slice(1, -1).join(''), 'base64');
if (keyType !== 'ec') {
ret.fulltype = 'ssh-' + keyType;
} else {
// ECDSA
var asnReader = new Ber.Reader(privData);
asnReader.readSequence();
asnReader.readInt();
asnReader.readString(Ber.OctetString, true);
asnReader.readByte(); // Skip "complex" context type byte
var offset = asnReader.readLength(); // Skip context length
if (offset !== null) {
asnReader._offset = offset;
switch (asnReader.readOID()) {
case '1.2.840.10045.3.1.7':
...
function readString(buffer, start, encoding, stream, cb, maxLen) { if (encoding && !Buffer.isBuffer(encoding) && typeof encoding !== 'string') { if (typeof cb === 'number') maxLen = cb; cb = stream; stream = encoding; encoding = undefined; } start || (start = 0); var bufferLen = buffer.length; var left = (bufferLen - start); var len; var end; if (start < 0 || start >= bufferLen || left < 4) { stream && stream._cleanup(cb); return false; } len = buffer.readUInt32BE(start, true); if (len > (maxLen || MAX_STRING_LEN) || left < (4 + len)) { stream && stream._cleanup(cb); return false; } start += 4; end = start + len; buffer._pos = end; if (encoding) { if (Buffer.isBuffer(encoding)) { buffer.copy(encoding, 0, start, end); return encoding; } else return buffer.toString(encoding, start, end); } else return buffer.slice(start, end); }
...
if (keyType !== 'ec') {
ret.fulltype = 'ssh-' + keyType;
} else {
// ECDSA
var asnReader = new Ber.Reader(privData);
asnReader.readSequence();
asnReader.readInt();
asnReader.readString(Ber.OctetString, true);
asnReader.readByte(); // Skip "complex" context type byte
var offset = asnReader.readLength(); // Skip context length
if (offset !== null) {
asnReader._offset = offset;
switch (asnReader.readOID()) {
case '1.2.840.10045.3.1.7':
// prime256v1/secp256r1
...
function verifyPPKMAC(keyInfo, passphrase, privateKey) { if (keyInfo._macresult !== undefined) return keyInfo._macresult; else if (!keyInfo.ppk) throw new Error("Key isn't a PPK"); else if (!keyInfo.privateMAC) throw new Error('Missing MAC'); else if (!privateKey) throw new Error('Missing raw private key data'); else if (keyInfo.encryption && typeof passphrase !== 'string') throw new Error('Missing passphrase for encrypted PPK'); else if (keyInfo.encryption && !keyInfo._decrypted) throw new Error('PPK must be decrypted before verifying MAC'); var mac = keyInfo.privateMAC; var typelen = keyInfo.fulltype.length; // encryption algorithm is converted at this point for use with OpenSSL, // so we need to use the original value so that the MAC is calculated // correctly var enc = (keyInfo.encryption ? 'aes256-cbc' : 'none'); var enclen = enc.length; var commlen = Buffer.byteLength(keyInfo.comment); var pub = keyInfo.public; var publen = pub.length; var privlen = privateKey.length; var macdata = new Buffer(4 + typelen + 4 + enclen + 4 + commlen + 4 + publen + 4 + privlen); var p = 0; macdata.writeUInt32BE(typelen, p, true); macdata.write(keyInfo.fulltype, p += 4, typelen, 'ascii'); macdata.writeUInt32BE(enclen, p += typelen, true); macdata.write(enc, p += 4, enclen, 'ascii'); macdata.writeUInt32BE(commlen, p += enclen, true); macdata.write(keyInfo.comment, p += 4, commlen, 'utf8'); macdata.writeUInt32BE(publen, p += commlen, true); pub.copy(macdata, p += 4); macdata.writeUInt32BE(privlen, p += publen, true); privateKey.copy(macdata, p += 4); if (typeof passphrase !== 'string') passphrase = ''; var mackey = crypto.createHash('sha1') .update('putty-private-key-file-mac-key', 'ascii') .update(passphrase, 'utf8') .digest(); var calcMAC = crypto.createHmac('sha1', mackey) .update(macdata) .digest('hex'); return (keyInfo._macresult = (calcMAC === mac)); }
...
var privateKey = new Buffer(m[5].replace(/\r?\n/g, ''), 'base64');
ret.privateMAC = m[6].replace(/\r?\n/g, '');
// automatically verify private key MAC if we don't need to wait for
// decryption
if (!ret.encryption) {
var valid = utils.verifyPPKMAC(ret, undefined, privateKey);
if (!valid)
throw new Error('PPK MAC mismatch');
}
// generate a PEM encoded version of the public key
var pubkey = utils.genPublicKey(ret);
ret.public = pubkey.public;
...