Skip to content

Commit

Permalink
Write two-way cipher/decipher for online mode.
Browse files Browse the repository at this point in the history
Also remove Redmi Note 4-specific issue as it was caused by lag.
  • Loading branch information
retrixe committed Dec 28, 2021
1 parent 4fa0849 commit e04763e
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 11 deletions.
1 change: 0 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
- Fix issue with split-screen when connected.
- Work on replacing auto /spawn with auto commands.
- Handle graceful disconnect when being hit by the OOM killer?
- Keyboard doesn't show up after tapping on chat field on Redmi Note 4.
- https://reactnative.dev/docs/performance (esp when logging in)
- Respect chat message length limits.
- OnePlus 3T titles are wrapped.
Expand Down
22 changes: 13 additions & 9 deletions src/minecraft/connection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
Cipher,
createCipheriv,
createDecipheriv,
createHash,
Decipher,
publicEncrypt
} from 'react-native-crypto'
import { InteractionManager } from 'react-native'
Expand Down Expand Up @@ -36,7 +38,8 @@ export class ServerConnection extends events.EventEmitter {
socket: net.Socket
disconnectTimer?: NodeJS.Timeout
disconnectReason?: string
aesDigest?: Cipher
aesDecipher?: Decipher
aesCipher?: Cipher

constructor(socket: net.Socket) {
super()
Expand All @@ -51,7 +54,8 @@ export class ServerConnection extends events.EventEmitter {
const packet = this.compressionEnabled
? makeBaseCompressedPacket(this.compressionThreshold, packetId, data)
: makeBasePacket(packetId, data)
return this.socket.write(packet, cb)
const toWrite = this.aesCipher ? this.aesCipher.update(packet) : packet
return this.socket.write(toWrite, cb)
}

onlyOneCloseCall = false
Expand Down Expand Up @@ -112,9 +116,11 @@ const initiateConnection = async (opts: {
// Run after interactions to improve user experience.
InteractionManager.runAfterInteractions(() => {
// Note: the entire packet is encrypted, including the length fields and the packet's data.
if (conn.aesDigest) newData = conn.aesDigest.update(newData)
// https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/src/transforms/encryption.js
let finalData = newData
if (conn.aesDecipher) finalData = conn.aesDecipher.update(newData)
// Buffer data for read.
conn.bufferedData = Buffer.concat([conn.bufferedData, newData])
conn.bufferedData = Buffer.concat([conn.bufferedData, finalData])
// ;(async () => { This would need a mutex.
while (true) {
const packet = conn.compressionEnabled
Expand Down Expand Up @@ -188,11 +194,6 @@ const initiateConnection = async (opts: {
'\n-----END PUBLIC KEY-----'
const encryptedSharedSecret = publicEncrypt(pk, sharedSecret)
const encryptedVerifyToken = publicEncrypt(pk, verifyToken)
conn.aesDigest = createCipheriv(
'aes-128-cfb8',
sharedSecret,
sharedSecret
)
// Send encryption response packet.
await conn.writePacket(
0x01,
Expand All @@ -204,6 +205,9 @@ const initiateConnection = async (opts: {
])
)
// From this point forward, everything is encrypted, including the Login Success packet.
const ss = sharedSecret
conn.aesDecipher = createDecipheriv('aes-128-cfb8', ss, ss)
conn.aesCipher = createCipheriv('aes-128-cfb8', ss, ss)
})().catch(() => {
conn.disconnectReason =
'{"text":"Failed to authenticate with Mojang servers!"}'
Expand Down
2 changes: 1 addition & 1 deletion src/screens/ServerScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ const ServerScreen = () => {
</>
) : (
<Text style={styles.serverDescription}>
{ping === null
{ping === null // LOW-TODO: No UI feedback when No route to host.
? 'Error while pinging...'
: 'Pinging...'}
</Text>
Expand Down

0 comments on commit e04763e

Please sign in to comment.