fix zlib decryption issue

This commit is contained in:
extremeheat 2021-01-30 02:36:34 -05:00
commit 040887e9df
3 changed files with 72 additions and 36 deletions

View file

@ -30,7 +30,7 @@
"BehaviourPackInfos": [
"array",
{
"countType": "varint",
"countType": "li16",
"type": [
"container",
[
@ -69,7 +69,7 @@
"TexturePackInfos": [
"array",
{
"countType": "varint",
"countType": "li16",
"type": [
"container",
[
@ -2402,11 +2402,11 @@
"type": "bool"
},
{
"name": "behaviorpackidversions",
"name": "behavior_pack_id_versions",
"type": "ResourcePackIdVersions"
},
{
"name": "resourcepackidversions",
"name": "resource_pack_id_versions",
"type": "ResourcePackIdVersions"
},
{

View file

@ -184,6 +184,7 @@ class Player extends EventEmitter {
if (buffer[0] == 0xfe) { // wrapper
if (this.encryptionEnabled) {
// console.log('READING ENCRYPTED PACKET', buffer)
this.decrypt(buffer.slice(1))
} else {
const stream = new BinaryStream(buffer)
@ -247,8 +248,7 @@ class Server extends EventEmitter {
const buffer = encapsulated.buffer
const client = this.clients[this.getAddrHash(inetAddr)]
if (!client) {
console.warn('packet from unknown inet addr', inetAddr.address, inetAddr.port)
return
throw new Error(`packet from unknown inet addr: ${inetAddr.address}/${inetAddr.port}`)
}
client.handle(buffer)
}
@ -273,9 +273,8 @@ let server = new Server({
})
server.create('0.0.0.0', 19130)
server.on('connect', (data) => {
// TODO: send other packets needed to login...
const client = data.client
server.on('connect', ({ client }) => {
/** @type {Player} */
client.on('join', () => {
console.log('Client joined', client.getData())

View file

@ -72,9 +72,9 @@ function createEncryptor(client, iv) {
// A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]).
// The send counter is represented as a little-endian 64-bit long and incremented after each packet.
const encryptor = new Transform({
const addChecksum = new Transform({ // append checksum
transform(chunk, enc, cb) {
console.log('Encryptor called', chunk)
console.log('Encryptor: checking checksum', chunk)
// Here we concat the payload + checksum before the encryption
const packet = Buffer.concat([chunk, computeCheckSum(chunk, client.sendCounter, client.secretKeyBytes)])
client.sendCounter++
@ -84,51 +84,74 @@ function createEncryptor(client, iv) {
})
// https://stackoverflow.com/q/25971715/11173996
// TODO: Fix deflate stream - for some reason using .pipe() doesn't work here
// so we deflate it outside the pipe
const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH })
const writableStream = new PassThrough()
// TODO: Fix deflate stream - for some reason using .pipe() doesn't work using zlib.createDeflateRaw()
// so we define our own compressor transform
// const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH })
const compressor = new Transform({
transform(chunk, enc, cb) {
Zlib.deflateRaw(chunk, { level: 7 }, (err, res) => {
if (err) {
console.error(err)
throw new Error(`Failed to deflate stream`)
}
this.push(res)
cb()
})
}
})
writableStream
// .pipe(compressor)
.pipe(encryptor).pipe(client.cipher).on('data', client.onEncryptedPacket)
const stream = new PassThrough()
stream
.pipe(compressor)
.pipe(addChecksum).pipe(client.cipher).on('data', client.onEncryptedPacket)
return (blob) => {
// console.log('ENCRYPTING')
Zlib.deflateRaw(blob, { level: 7 }, (err, res) => {
if (err) {
console.error(err)
throw new Error(`Failed to deflate stream`)
}
writableStream.write(res)
})
// writableStream.write(blob)
stream.write(blob)
}
}
function createDecryptor(client, iv) {
client.decipher = createDecipher(client.secretKeyBytes, iv)
client.receiveCounter = client.receiveCounter || 0n
const decryptor = new Transform({
const verifyChecksum = new Transform({ // verify checksum
transform(chunk, encoding, cb) {
console.log('Got transform', chunk)
console.log('Decryptor: checking checksum', chunk)
const packet = chunk.slice(0, chunk.length - 8);
const checksum = chunk.slice(chunk.length - 8);
const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes)
console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch')
client.receiveCounter++
if (checksum.toString("hex") == computedCheckSum.toString("hex")) this.push(packet)
else console.log('FAILED', checksum.toString("hex"), computedCheckSum.toString("hex"))
// else process.exit(`Checksum mismatch ${checksum.toString("hex")} - ${computedCheckSum.toString("hex")}`) // TODO: remove
if (checksum.toString("hex") == computedCheckSum.toString("hex")) {
this.push(packet)
} else {
throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`)
}
// console.log('Calling cb')
cb()
}
})
client.decipher.pipe(decryptor)
.pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 }))
.on('data', client.onDecryptedPacket)
// .on('end', () => console.log('Finished!'))
const inflator = new Transform({
transform(chunk, enc, cb) {
// console.log('INFLATING')
Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => {
if (err) throw err
this.push(buf)
cb()
})
}
})
client.decipher.pipe(verifyChecksum)
.pipe(inflator)
// .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 }))
.on('data', (...args) => client.onDecryptedPacket(...args))
.on('end', () => console.log('Decryptor: finish pipeline'))
return (blob) => {
client.decipher.write(blob)
@ -138,3 +161,17 @@ function createDecryptor(client, iv) {
module.exports = {
createCipher, createDecipher, createEncryptor, createDecryptor
}
function testDecrypt() {
const client = {
secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'),
onDecryptedPacket: (...data) => console.log('Decrypted', data)
}
const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64')
const decrypt = createDecryptor(client, iv)
console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex')))
console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex')))
}
// testDecrypt()