Skip to content

fix: wrap base64-encoded PEM with 64-char line boundary#1292

Merged
rom1504 merged 1 commit intoPrismarineJS:masterfrom
littledivy:rfc7468_pem
Jul 27, 2025
Merged

fix: wrap base64-encoded PEM with 64-char line boundary#1292
rom1504 merged 1 commit intoPrismarineJS:masterfrom
littledivy:rfc7468_pem

Conversation

@littledivy
Copy link
Contributor

According to RFC7468:

Generators MUST wrap the base64-encoded lines so that each line
consists of exactly 64 characters except for the final line, which
will encode the remainder of the data (within the 64-character line
boundary), and they MUST NOT emit extraneous whitespace.

Parsers can avoid branching and prevent timing sidechannel attacks. Ref https://arxiv.org/pdf/2108.04600.pdf

Fixes compatibility with Deno as it enforces stricter handling of PEM.

@rom1504
Copy link
Member

rom1504 commented Mar 17, 2024

how did you check this improve something?

@rom1504
Copy link
Member

rom1504 commented Jun 2, 2024

Hi @littledivy if nobody can verify that fix solve some issues, I think we should close this PR

@ozaner
Copy link

ozaner commented Jul 24, 2024

Hey @rom1504 this solves Deno compatibility. Without this fix, the node-minecraft-protocol library would only work with the NodeJS runtime and not others that have properly implemented RFC7468 (i.e. Deno). I've verified that this is a blocker towards that goal.

@rom1504
Copy link
Member

rom1504 commented Jul 25, 2024

What example were you able to run with deno?

@extremeheat
Copy link
Member

It may be the standard length, but for Minecraft we'd likely want to match the encoding behavior to be like vanilla Minecraft otherwise it's one of the areas that can be easily flagged by server software (like anticheat, antibot, etc).

I'm looking into the vanilla behavior here.

Copy link
Member

@extremeheat extremeheat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let pem = '-----BEGIN RSA PUBLIC KEY-----\n'
let base64PubKey = mcPubKeyBuffer.toString('base64')
const maxLineLength = 76
const maxLineLength = 64
Copy link
Member

@extremeheat extremeheat Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For server/ we can keep it at 76 (but it probably won't matter whatever the width is as vanilla client doesn't care). It's not going to break Deno or anything as this call result isn't passed to anything except being sent to clients.

let pem = '-----BEGIN PUBLIC KEY-----\n'
let base64PubKey = mcPubKeyBuffer.toString('base64')
const maxLineLength = 65
const maxLineLength = 64
Copy link
Member

@extremeheat extremeheat Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the client/ width seems to not matter at all as it's not sent to server or anything but just as an intermediate variable that we pass to encrypt method -

const pubKey = mcPubKeyToPem(packet.publicKey)

@ozaner
Copy link

ozaner commented Jul 25, 2024

I see. Honestly, even though I didn't make this PR, I think it should be closed.

The main purpose of this PR was to enable Deno support, but since changing these widths seems to go against the actual Minecraft protocol, and since more work beyond changing these widths would probably need to be done to make it compatible with Deno, it doesn't seem worth it.

A full on proper port of this package is probably necessary for anyone wanting to use it with Deno (or better Deno-Node compatibility) which is definitely not in the scope of this project.

Thanks @extremeheat for helping to investigate this though.

@extremeheat
Copy link
Member

No, what I said was that only the client PEM encoder method needs to be changed, and that changing it here would have no effect on anything (beyond maybe fixing Deno). The width doesn't matter to nmp as long as it can be read by the crypto call.

On the server code there is nothing to change

@ozaner
Copy link

ozaner commented Oct 11, 2024

As of the release of Deno 2.0, Deno now has full backwards compatibility with npm packages. I've verified that this package (and thus the packages that depend on it like mineflayer) does indeed work with Deno 2.0.

So I think we should finally close this PR now.

@interrrp
Copy link

interrrp commented Oct 31, 2024

As of the release of Deno 2.0, Deno now has full backwards compatibility with npm packages. I've verified that this package (and thus the packages that depend on it like mineflayer) does indeed work with Deno 2.0.

So I think we should finally close this PR now.

As of Deno 2.0.4, the issue arises yet again:

$ deno --version
deno 2.0.4 (stable, release, x86_64-pc-windows-msvc)
v8 12.9.202.13-rusty
typescript 5.6.2

$ deno task dev 
Task dev deno run -A --watch src/main.ts
Watcher Process started.
error: Uncaught Error: ASN.1 error: PEM error: PEM Base64 error: invalid Base64 encoding

Update: I downgraded to previous Mineflayer and Minecraft versions (down to 1.12.2!), and they all showed the same error. I believe this PR should be reopened.

@ozaner
Copy link

ozaner commented Nov 1, 2024

@interrrp can you send your Deno code? I just tried it with Deno 2.0.4 on Minecraft 1.20.4 and it was able to join my local server just fine. Here is my code:

import { createBot } from 'npm:mineflayer'

const bot = createBot({
  host: "localhost",
  port: 25565,
  username: 'TestBot',
});

bot.on('chat', (username, message) => {
  if (username === bot.username) return
  bot.chat(message)
})

@interrrp
Copy link

interrrp commented Nov 1, 2024

@interrrp can you send your Deno code? I just tried it with Deno 2.0.4 on Minecraft 1.20.4 and it was able to join my local server just fine. Here is my code:

import { createBot } from 'npm:mineflayer'

const bot = createBot({
  host: "localhost",
  port: 25565,
  username: 'TestBot',
});

bot.on('chat', (username, message) => {
  if (username === bot.username) return
  bot.chat(message)
})

It's a bit complicated, mine was loading from an external file. However, I tried your code, and it still did not work under the same Deno and Minecraft versions.

image

@ozaner
Copy link

ozaner commented Nov 1, 2024

Yeah honestly not sure what the problem is. I tried running it as a .ts file, using watcher mode instead of running directly, and it still works for me.

All I can think of is that you aren't on Deno 2.0 but you apparently are. Well, in any case, I think your PR is a good change and would probably fix this.

@Asguho
Copy link

Asguho commented Nov 28, 2024

i also get the same error, when trying the code in mc 1.20.4 and deno 2.1.1:

Uncaught Error: ASN.1 error: PEM error: PEM Base64 error: invalid Base64 encoding
    at Object.publicEncrypt (ext:deno_node/internal/crypto/cipher.ts:221:10)
    at sendEncryptionKeyResponse (file:///C:/Users/aske/Documents/GitHub/deno-mineflayer/node/node_modules/.deno/minecraft-protocol@1.50.0/node_modules/minecraft-protocol/src/client/encrypt.js:49:52)
    at gotSharedSecret (file:///C:/Users/aske/Documents/GitHub/deno-mineflayer/node/node_modules/.deno/minecraft-protocol@1.50.0/node_modules/minecraft-protocol/src/client/encrypt.js:28:9)
    at ext:deno_node/internal/crypto/_randomBytes.ts:42:9
    at callback (ext:deno_web/02_timers.js:58:7)
    at eventLoopTick (ext:core/01_core.js:210:13)

@Asguho
Copy link

Asguho commented Nov 28, 2024

Since the premise for closing this PR was that Deno had implemented full backward compatibility, and this is not the case, would it be possible to reopen it?

@Nexus-00
Copy link

i also get the same error, when trying the code in mc 1.20.4 and deno 2.1.1:

Uncaught Error: ASN.1 error: PEM error: PEM Base64 error: invalid Base64 encoding
    at Object.publicEncrypt (ext:deno_node/internal/crypto/cipher.ts:221:10)
    at sendEncryptionKeyResponse (file:///C:/Users/aske/Documents/GitHub/deno-mineflayer/node/node_modules/.deno/minecraft-protocol@1.50.0/node_modules/minecraft-protocol/src/client/encrypt.js:49:52)
    at gotSharedSecret (file:///C:/Users/aske/Documents/GitHub/deno-mineflayer/node/node_modules/.deno/minecraft-protocol@1.50.0/node_modules/minecraft-protocol/src/client/encrypt.js:28:9)
    at ext:deno_node/internal/crypto/_randomBytes.ts:42:9
    at callback (ext:deno_web/02_timers.js:58:7)
    at eventLoopTick (ext:core/01_core.js:210:13)

I can confirm that as of Deno version 2.2.4, the error remains.

@extremeheat extremeheat reopened this Mar 20, 2025
According to [RFC7468](https://datatracker.ietf.org/doc/html/rfc7468)

> Generators MUST wrap the base64-encoded lines so that each line
  consists of exactly 64 characters except for the final line, which
  will encode the remainder of the data (within the 64-character line
  boundary), and they MUST NOT emit extraneous whitespace.

Parsers can avoid branching and prevent timing sidechannel attacks. Ref https://arxiv.org/pdf/2108.04600.pdf

Fixes compatibility with Deno as it enforces stricter handling of PEM.
@littledivy
Copy link
Contributor Author

@extremeheat Sorry for the delay, I have reverted the server change.

@LunarLollipop
Copy link

error: Uncaught Error: ASN.1 error: PEM error: PEM Base64 error: invalid Base64 encoding at Object.publicEncrypt (ext:deno_node/internal/crypto/cipher.ts:220:22) at sendEncryptionKeyResponse (file:///Users/luna/deno/node_modules/minecraft-protocol/src/client/encrypt.js:49:52)

Issue still exists in deno 2.2.11. and minecraft_protocol 1.57.0

I tried manually change from 65 -> 64 in node_modules (locally) and this fixed issue with creating bot.

Is there a specific reason 65 is used? If no, I hope this will be merged soon.

@CubeBeveled
Copy link

burh please merge this

i couldnt get nodejs to work so am using deno

@extremeheat
Copy link
Member

I tried manually change from 65 -> 64 in node_modules (locally) and this fixed issue with creating bot.

Can anyone verify this ? cc @CubeBeveled

@interrrp
Copy link

Issue is still present as of Mineflayer 4.30.0 and Deno 2.4.2
Applying the change on ~/.cache/deno/npm/registry.npmjs.org/minecraft-protocol/1.58.0/src/client/encrypt.js manually will fix it

@rom1504 rom1504 merged commit 0f6da56 into PrismarineJS:master Jul 27, 2025
28 checks passed
@rom1504
Copy link
Member

rom1504 commented Jul 27, 2025

This seems to help in some cases while not breaking anything. Merged.

@rom1504
Copy link
Member

rom1504 commented Jul 27, 2025

/makerelease

@rom1504bot rom1504bot mentioned this pull request Jul 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Closed

Development

Successfully merging this pull request may close these issues.

9 participants