fix zlib decryption issue
This commit is contained in:
parent
d578eae98f
commit
040887e9df
3 changed files with 72 additions and 36 deletions
|
|
@ -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"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue