Files
minecraft_protocol/05-login-encryption.md
T
claude-timemachine d73c1c9537 minecraft_protocol: foundation + per-version protocol docs 1.7.10->26.2
8 topical docs (overview, data types, lifecycle, handshake, status/ping,
login+encryption, configuration, version-differences) + proxy-forwarding set
+ 16 per-version release-line docs, sourced from minecraft.wiki, ViaVersion
(source + commits), minecraft-data, node-minecraft-protocol, Velocity, BungeeCord.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:15:32 +02:00

27 KiB
Raw Blame History

05 — Login State, Encryption & Compression

Scope: Java Edition 1.7.10 → latest (1.21.x). Covers the Login protocol state, the encryption handshake, Mojang session auth, packet compression, and the 1.19/1.20.2 versioned deviations. All crypto details are sourced from the reference implementations listed in each section.


1. Login State Overview

The Login state begins immediately after the client sends a Handshake packet with next state = 2. It ends when the server sends Login Success (and, since 1.20.2, the client acknowledges it). All packets in this state use the standard framing:

<Packet Length: VarInt>  <Packet ID: VarInt>  <Data: bytes>

After Set Compression is negotiated (if at all), each packet gains an extra Data Length VarInt (see §4). After Encryption Response is processed, the entire TCP stream — including the Length prefix — is encrypted with AES/CFB8 (see §3).


2. Packet Reference

2.1 Login Start (0x00 Serverbound)

The first Login-state packet sent by the client.

Field Type Version range Notes
Username String(16) all Player username, max 16 chars
Signature Optional container 1.191.19.2 Profile public key; see §5
└ Timestamp i64 1.191.19.2 Key expiry timestamp (ms since epoch)
└ Public Key Prefixed byte array 1.191.19.2 DER SubjectPublicKeyInfo of player's key
└ Signature Prefixed byte array 1.191.19.2 Mojang-signed; see §5
Has UUID Optional bool (not present in 1.20.2+) 1.19.11.20.1 Presence flag
Player UUID UUID 1.19.1+ Optional (flag-gated) in 1.19.11.20.1; always present 1.20.2+

Source: minecraft-data/data/pc/1.7/protocol.json, minecraft-data/data/pc/1.19/protocol.json, minecraft-data/data/pc/1.19.2/protocol.json, minecraft-data/data/pc/1.20.2/protocol.json; BungeeCord/protocol/src/main/java/net/md_5/bungee/protocol/packet/LoginRequest.java:2839

Version notes:

  • ≤1.19.2: Signature container present (profile public key for chat-signing); removed in 1.19.3.
    • 1.19: only signature field (no UUID).
    • 1.19.2: adds optional playerUUID after the signature.
  • 1.19.11.20.1: UUID is optional (preceded by a boolean flag).
  • 1.20.2+: UUID is unconditionally included (no flag byte). (BungeeCord LoginRequest.java:3538: if (protocolVersion >= MINECRAFT_1_20_2) reads UUID directly.)

2.2 Encryption Request (0x01 Clientbound)

Sent by the server in online mode to initiate the key exchange.

Field Type Version range Notes
Server ID String(20) all Historically a 10-char hex; empty string "" in vanilla 1.7+
Public Key Prefixed byte array 1.8+ DER-encoded X.509 SubjectPublicKeyInfo of server's RSA-1024 public key
Public Key 2-byte-length byte array 1.7 (pre-Netty) Same key, length prefixed with i16
Verify Token Prefixed byte array all 4 random bytes generated per-connection
Should Authenticate Boolean 1.20.5+ Whether Mojang session auth should be performed

Source: Velocity/proxy/.../EncryptionRequestPacket.java:6274 (1.7 vs 1.8+ branching on readByteArray vs readByteArray17; shouldAuthenticate field read at line 6769); BungeeCord/protocol/.../EncryptionRequest.java:2630; minecraft-data/data/pc/1.7/protocol.json (countType i16); minecraft-data/data/pc/1.8/protocol.json (countType varint).

Notes:

  • The Server ID string was meaningful in old Alpha/Beta versions but has been an empty string "" in all vanilla servers since 1.7 (wiki.minecraft.net/w/Java_Edition_protocol/Encryption). Some implementations (node-minecraft-protocol server/login.js:89) generate a short random hex string instead.
  • shouldAuthenticate (1.20.5+) lets the server tell the client not to call the Mojang session endpoint; used for offline-mode negotiation without breaking the encryption handshake. (Velocity/proxy/.../EncryptionRequestPacket.java:6769)

2.3 Encryption Response (0x01 Serverbound)

Client reply containing the RSA-encrypted shared secret and token.

Standard form (all versions except 1.191.19.2 with profile keys):

Field Type Notes
Shared Secret Prefixed byte array 128 bytes (RSA-PKCS1 v1.5 ciphertext of 16-byte secret)
Verify Token Prefixed byte array 128 bytes (RSA-PKCS1 v1.5 ciphertext of the 4-byte token)

1.191.19.2 form with profile keys (chat signing enabled):

Field Type Notes
Shared Secret Prefixed byte array 128 bytes as above
Has Verify Token Boolean true = standard token; false = signed salt
— if true: Verify Token Prefixed byte array 128 bytes as above
— if false: Salt i64 Random 64-bit salt
— if false: Message Signature Prefixed byte array SHA256withRSA sig over verifyToken ‖ salt

Source: Velocity/proxy/.../EncryptionResponsePacket.java:66101 (version branching); BungeeCord/protocol/.../EncryptionResponse.java:2455; node-minecraft-protocol/src/client/encrypt.js:5273 (1.19 hasVerifyToken/salt/messageSignature branch); node-minecraft-protocol/src/server/login.js:109141 (server-side verification).

Notes:

  • Has Verify Token = false only occurs in 1.191.19.2 when the client has a profile key (chat-signing enabled). The server verifies the salt+signature against the player's profile public key from Login Start instead of decrypting the token. (server/login.js:120126: crypto.verify('sha256WithRSAEncryption', …))
  • In 1.19.3+, profile keys were removed from Login Start; Has Verify Token field is gone and the packet reverts to the simple two-field form. (Velocity/proxy/.../EncryptionResponsePacket.java:7074: version range >= 1.19 && < 1.19.3)

2.4 Set Compression (0x03 Clientbound)

Optional packet. If sent, all subsequent packets in Login (and Play) use the compressed framing described in §4.

Field Type Notes
Threshold VarInt Minimum uncompressed size to trigger compression. Negative = disable.

Source: BungeeCord/protocol/.../SetCompression.java:1922; node-minecraft-protocol/src/server/login.js:179181 (client.write('compress', { threshold: 256 })).

Notes:

  • Added in 1.8 (protocol version 47, snapshot 14w28a). (node-minecraft-protocol/src/server/login.js:179: if (client.protocolVersion >= 27))
  • Vanilla default threshold is 256 bytes uncompressed payload.
  • A threshold of -1 disables compression; packets keep the uncompressed framing.
  • Must be sent before Login Success if used. The server enables its own compressor and decompressor as soon as it sends this packet; the client enables them on receipt.

2.5 Login Success (0x02 Clientbound)

Signals the end of authentication. Carries the player's resolved UUID and username.

Field Type Version range Notes
UUID String (hyphenated) ≤1.15 "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
UUID UUID (128-bit wire) 1.16+ Raw 16-byte big-endian UUID
Username String(16) all Canonical (case-corrected) name from Mojang
Properties Array of Property 1.19+ Texture/cape data; each has name, value, optional signature
Strict Error Handling Boolean 1.20.51.21.1 Vanilla sends true

Source: BungeeCord/protocol/.../LoginSuccess.java:2843 (UUID wire-type branch at 1.16; properties at 1.19; strictErrorHandling at 1.20.51.21.1); node-minecraft-protocol/src/server/login.js:184188.

Notes:

  • UUID comes from the Mojang session server response (id field, dashes stripped) in online mode. In offline mode it is UUID.nameUUIDFromBytes("OfflinePlayer:" + username).
  • Login Success is sent encrypted (all prior negotiation including Encryption Response triggers immediate cipher switch; see §3.5).

2.6 Login Acknowledged (0x03 Serverbound)

No fields. The client sends this to confirm it has processed Login Success and is ready to enter the Configuration state. Added in 1.20.2.

Source: minecraft-data/data/pc/1.20.2/protocol.json (toServer 0x03: login_acknowledged); node-minecraft-protocol/src/server/login.js:189191 (if (client.supportFeature('hasConfigurationState')) client.once('login_acknowledged', …)); minecraft-data/data/pc/common/features.json (hasConfigurationState versions: ["1.20.2", "latest"]).


3. Encryption Handshake

3.1 Sequence Diagram

sequenceDiagram
    participant C as Client
    participant S as Server
    participant M as sessionserver.mojang.com

    C->>S: Handshake (next_state=2)
    C->>S: Login Start (username [+ profile key 1.191.19.2])
    Note over S: online-mode? generate RSA-1024 keypair (once at startup)
    S->>C: Encryption Request (serverId="", DER pubkey, 4-byte verifyToken)
    Note over C: generate 16-byte random sharedSecret
    Note over C: RSA-PKCS1-v1.5 encrypt sharedSecret → enc_secret (128 B)
    Note over C: RSA-PKCS1-v1.5 encrypt verifyToken → enc_token  (128 B)
    Note over C: compute serverIdHash = MinecraftSHA1(serverId‖sharedSecret‖pubKey)
    C->>M: POST /session/minecraft/join {accessToken, selectedProfile, serverId=serverIdHash}
    M-->>C: 204 No Content
    C->>S: Encryption Response (enc_secret, enc_token)
    Note over C: enable AES/CFB8 (key=sharedSecret, IV=sharedSecret) — all outgoing encrypted now
    Note over S: RSA-decrypt enc_secret → sharedSecret
    Note over S: RSA-decrypt enc_token → verify == original verifyToken?
    Note over S: compute serverIdHash = MinecraftSHA1(serverId‖sharedSecret‖pubKey)
    S->>M: GET /session/minecraft/hasJoined?username=&serverId=serverIdHash
    M-->>S: 200 {id, name, properties} or 204 (not found)
    Note over S: enable AES/CFB8 (key=sharedSecret, IV=sharedSecret) — all outgoing encrypted now
    S->>C: [Set Compression] (optional, 1.8+)
    S->>C: Login Success (uuid, username, properties) — encrypted
    C->>S: Login Acknowledged (1.20.2+) — encrypted

3.2 RSA Key Exchange

Key size: 1024-bit RSA, generated once at server startup.

  • BungeeCord: EncryptionUtil.java:51generator.initialize(1024)
  • Velocity: VelocityServer.java:255EncryptionUtils.createRsaKeyPair(1024)

Public key encoding: The bytes sent in Encryption Request are the DER-encoded X.509 SubjectPublicKeyInfo (i.e. java.security.PublicKey.getEncoded() using the X509EncodedKeySpec). This wraps the raw RSA key in an ASN.1 structure identifying the algorithm (rsaEncryption OID 1.2.840.113549.1.1.1).

The client reconstructs the public key from this DER blob: (node-minecraft-protocol/src/client/encrypt.js:4850)

// encrypt.js:4850
const pubKey = mcPubKeyToPem(packet.publicKey)   // DER → PEM wrapper
const encryptedSharedSecretBuffer =
  crypto.publicEncrypt({ key: pubKey, padding: crypto.constants.RSA_PKCS1_PADDING }, sharedSecret)
const encryptedVerifyTokenBuffer =
  crypto.publicEncrypt({ key: pubKey, padding: crypto.constants.RSA_PKCS1_PADDING }, packet.verifyToken)

Padding: PKCS#1 v1.5 (RSA_PKCS1_PADDING / RSA/ECB/PKCS1Padding).

  • BungeeCord: EncryptionUtil.java:144148Cipher.getInstance("RSA/ECB/PKCS1Padding")
  • Velocity: EncryptionUtils.java:190193Cipher.getInstance("RSA") (JCA default = PKCS#1 v1.5)

Ciphertext size: With a 1024-bit key and PKCS#1 v1.5 padding, any input ≤ 117 bytes produces a 128-byte ciphertext. Both the encrypted shared secret and encrypted verify token are therefore 128 bytes on the wire.


3.3 Server-ID Hash Algorithm

The serverIdHash (called serverId in the Mojang API) is a non-standard SHA-1 digest formatted as a signed two's-complement hex integer, possibly with a leading -.

Inputs (in order):

  1. serverId string bytes, encoded as ISO-8859-1 (Latin-1) — in vanilla this is always an empty string, so no bytes are contributed.
  2. sharedSecret — the raw 16-byte AES key.
  3. Server's RSA public key — DER-encoded SubjectPublicKeyInfo bytes.

Algorithm:

import hashlib, textwrap

def minecraft_sha1_hex(server_id: str, shared_secret: bytes, server_pub_der: bytes) -> str:
    h = hashlib.sha1()
    h.update(server_id.encode('iso-8859-1'))
    h.update(shared_secret)
    h.update(server_pub_der)
    digest = h.digest()                          # 20 raw bytes
    # Interpret as a signed big-endian integer (two's complement):
    n = int.from_bytes(digest, byteorder='big', signed=True)
    return format(n, 'x')                        # hex, with '-' prefix if negative

Java equivalent (BungeeCord InitialHandler.java:517525):

MessageDigest sha = MessageDigest.getInstance("SHA-1");
sha.update(request.getServerId().getBytes("ISO_8859_1"));
sha.update(sharedKey.getEncoded());
sha.update(EncryptionUtil.keys.getPublic().getEncoded());
String hash = new BigInteger(sha.digest()).toString(16);
// BigInteger(byte[]) treats the input as two's-complement big-endian → negative if MSB set

Velocity (EncryptionUtils.java:203212) omits the serverId update because the field is always "" in Velocity:

digest.update(sharedSecret);      // EncryptionUtils.java:207
digest.update(key.getEncoded());  // EncryptionUtils.java:208
return twosComplementHexdigest(digest.digest());
// twosComplementHexdigest: new BigInteger(digest).toString(16)  (line 179)

Wiki examples (minecraft.wiki/w/Java_Edition_protocol/Encryption):

Input string serverIdHash
Notch 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
jeb_ -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
simon 88e16a1019277b15d58faf0541e11910eb756f6

Note: these examples use the string as the entire input (simulating a server where serverId = "Notch" etc.), not a realistic scenario.

Why two's complement? The SHA-1 output is 20 bytes. Mojang's original Minecraft code treated this raw byte array as a signed big-endian integer via Java's BigInteger(byte[]). If the high bit of the first byte is set (digest[0] ≥ 0x80), the integer is negative, and the hex string gets a leading -. This is non-standard but has been the canonical format since Minecraft Beta 1.2.


3.4 AES/CFB8 Stream Cipher

After both sides process Encryption Response, every subsequent byte on the TCP connection is encrypted. There are no unencrypted bytes after this point — not even the packet length VarInt.

Cipher parameters:

Parameter Value
Algorithm AES
Mode CFB8 (Cipher Feedback, 8-bit segment size)
Key 16-byte shared secret
IV 16-byte shared secret (same as key)
Padding None

BungeeCord (JavaCipher.java):

this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
cipher.init(mode, key, new IvParameterSpec(key.getEncoded()));
// key.getEncoded() == the 16-byte shared secret, used as IV

Velocity (JavaVelocityCipher.java:5061):

this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
this.cipher.init(
    encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE,
    key,
    new IvParameterSpec(key.getEncoded())   // IV = key = shared secret
);

node-minecraft-protocol (transforms/encryption.js:617):

// encryption.js:69
function createCipher(secret) {
  if (crypto.getCiphers().includes('aes-128-cfb8')) {
    return crypto.createCipheriv('aes-128-cfb8', secret, secret)  // key=secret, IV=secret
  }
  return new Cipher(secret)  // fallback uses aes-js CFB with segment size 1 byte
}

Important: Reusing the key as the IV is a known weakness (noted in Velocity source, JavaVelocityCipher.java:5258: "reusing the key as the IV defeats the entire point"). The cipher is initialized this way by Mojang design; it cannot be changed without a protocol breaking change.

Continuous operation: The AES/CFB8 state is maintained across packets. The cipher is never reset or re-initialized between packets; the feedback register carries over.


3.5 Timing: When Encryption Activates

  • Client: enables AES/CFB8 immediately after sending Encryption Response (node-minecraft-protocol/src/client/encrypt.js:73: client.setEncryption(sharedSecret))
  • Server: enables AES/CFB8 after receiving Encryption Response and verifying it (node-minecraft-protocol/src/server/login.js:150: client.setEncryption(sharedSecret); Velocity InitialLoginSessionHandler.java:234: mcConnection.enableEncryption(decryptedSharedSecret))

The server enables encryption before calling the Mojang session server, so if hasJoined fails, the server sends a disconnect packet that is already encrypted.


4. Session Authentication (Online Mode)

4.1 Client → Mojang: join

Before sending Encryption Response, the client posts to the Mojang session server:

POST https://sessionserver.mojang.com/session/minecraft/join
Content-Type: application/json

{
  "accessToken": "<launcher access token>",
  "selectedProfile": "<UUID of player, dashes removed>",
  "serverId": "<serverIdHash>"
}

Expected response: 204 No Content on success.

(node-minecraft-protocol/src/client/encrypt.js:4143: yggdrasilServer.join(accessToken, selectedProfile.id, packet.serverId, sharedSecret, packet.publicKey, cb) — the join call in the yggdrasil library computes the hash internally from serverId + sharedSecret + publicKey.)

4.2 Server → Mojang: hasJoined

After enabling encryption and verifying the token, the server queries:

GET https://sessionserver.mojang.com/session/minecraft/hasJoined
    ?username=<username>
    &serverId=<serverIdHash>
    [&ip=<client_ip>]          # optional; prevents proxy-hopping
  • 200 OK → body is a GameProfile JSON {id, name, properties[]}. Login proceeds.
  • 204 No Content → client did not call join; kick with "offline_mode_player" or similar.

(Velocity/proxy/.../InitialLoginSessionHandler.java:6871: URL template; BungeeCord InitialHandler.java:527528: URL construction with URLEncoder.encode.)

4.3 Mojang → Microsoft Account Migration

The original sessionserver.mojang.com endpoints still work after the Mojang → Microsoft account migration. All Minecraft clients (Bedrock and Java launcher) now use Microsoft OAuth tokens internally, but the session server interface is unchanged at the API level.

4.4 Offline Mode

In offline mode, the server skips:

  • Sending Encryption Request (no encryption handshake at all)
  • Calling hasJoined

UUID is derived deterministically: UUID.nameUUIDFromBytes("OfflinePlayer:" + username) (MD5-based UUID v3 equivalent). (BungeeCord/proxy/.../connection/InitialHandler.java:560)


5. 1.19 Profile Public Keys (Chat Signing)

Minecraft 1.19 introduced per-player RSA key pairs signed by Mojang, allowing chat message signing. The Login Start packet gained a Signature field to deliver the player's public key to the server.

This only affects the login phase through two mechanisms:

  1. Login Start (1.191.19.2): Client sends its profile public key (DER + Mojang signature).
  2. Encryption Response (1.191.19.2): Client may replace the encrypted verify token with a salt + signature over verifyToken ‖ salt, proving possession of the private key corresponding to the profile key.

Profile Key Container (in Login Start, 1.191.19.2)

Sub-field Type Notes
Timestamp i64 Key expiry in milliseconds since epoch
Public Key Prefixed byte array DER SubjectPublicKeyInfo
Signature Prefixed byte array Mojang signature over the key material

Signature verification (server side):

  • 1.19: verify against Mojang's public key over UTF8(expiryTimestamp + PEM(playerPubKey)). (node-minecraft-protocol/src/server/login.js:72: Buffer.from(timestamp + mcPubKeyToPem(publicKey), 'utf8'))
  • 1.19.2 (profileKeySignatureV2): verify against Mojang's public key over UUID(playerUUID) ‖ i64(timestamp) ‖ DER(playerPubKey). (node-minecraft-protocol/src/server/login.js:71: concat('UUID', playerUUID, 'i64', timestamp, 'buffer', publicKey.export({type:'spki', format:'der'})))
  • Both use RSA-SHA1 (crypto.verify('RSA-SHA1', …)).

(minecraft-data/data/pc/common/features.json: signatureEncryption active on ["1.19", "1.19.2"]; profileKeySignatureV2 active on ["1.19.2", "latest"].)

Removal in 1.19.3

Profile keys were removed from Login Start in 1.19.3. The Signature field is absent, the Has Verify Token field in Encryption Response is also gone, and the standard two-field Encryption Response format is used again.

(Velocity/proxy/.../EncryptionResponsePacket.java:7074: if (version.noLessThan(MINECRAFT_1_19) && version.lessThan(MINECRAFT_1_19_3)) { salt check })


6. Compression

6.1 Negotiation

The server may send Set Compression (0x03 clientbound) at any point during the Login state, before Login Success. The threshold value (VarInt) controls when zlib is applied:

  • threshold < 0 — compression is disabled (revert to uncompressed framing).
  • threshold = 0 — compress all packets.
  • threshold > 0 (common: 256) — compress only packets whose uncompressed data length exceeds the threshold.

Compression was added in 1.8 (snapshot 14w28a, protocol version 47). (node-minecraft-protocol/src/server/login.js:179: if (client.protocolVersion >= 27))

6.2 Packet Format Before Set Compression

┌─────────────────────────────────────────────────────────┐
│ Packet Length  (VarInt)  — byte count of ID + Data      │
│ Packet ID      (VarInt)                                  │
│ Data           (bytes)                                   │
└─────────────────────────────────────────────────────────┘

6.3 Packet Format After Set Compression

Two VarInts precede the payload:

┌─────────────────────────────────────────────────────────┐
│ Packet Length  (VarInt)  — byte count of (Data Length   │
│                            VarInt + possibly compressed  │
│                            ID+Data)                     │
│ Data Length    (VarInt)  — 0 = not compressed;          │
│                            >0 = uncompressed byte count  │
│ Packet ID + Data  (bytes) — zlib-compressed if DL>0,    │
│                             raw otherwise               │
└─────────────────────────────────────────────────────────┘

Uncompressed case (data length < threshold):

  • Data Length VarInt = 0
  • ID + Data follow uncompressed

Compressed case (data length ≥ threshold):

  • Data Length VarInt = uncompressed byte count of ID+Data
  • ID + Data bytes are zlib (DEFLATE) compressed

BungeeCord implementation (netty/LengthPrependerAndCompressor.java:4793):

// uncompressed path (line 5463):
if (oldBodyLen < threshold) {
    DefinedPacket.writeVarInt(oldBodyLen + 1, lenBuf); // Packet Length
    lenBuf.writeByte(0);                               // Data Length = 0 → uncompressed
    // ... append raw body ...
}
// compressed path (line 7893):
else {
    DefinedPacket.writeVarInt(oldBodyLen, buf);        // Data Length = original size
    zlib.process(msg, buf);                            // compress
    // Packet Length written as VarInt in front
}

6.4 Interaction with Encryption

Compression and encryption are independent layers. When both are active:

  1. Write path: Compress → Encrypt → TCP
  2. Read path: TCP → Decrypt → Decompress

The encrypted bytestream carries compressed packet data; the AES/CFB8 cipher sees compressed bytes and does not know about packet boundaries.


7. Version Summary

Feature Introduced Removed / Changed
Login Start: basic (name only) 1.7
Encryption request/response 1.2.5 (Beta)
Byte arrays length-prefixed with VarInt 1.8
Set Compression packet 1.8 (14w28a)
Login Start: profile public key 1.19 Removed 1.19.3
Encryption Response: Has Verify Token + salt 1.19 Removed 1.19.3
Login Start: optional UUID 1.19.1 Mandatory 1.20.2+
Profile key signature V2 1.19.2
Login Acknowledged packet 1.20.2
Configuration state after login 1.20.2
Encryption Request: Should Authenticate 1.20.5
Login Success: Strict Error Handling 1.20.5 Removed 1.21.2
Login Success: UUID as raw 128-bit wire type 1.16
Login Success: Properties array 1.19

8. Sources

Reference Path
node-minecraft-protocol encrypt.js node-minecraft-protocol/src/client/encrypt.js
node-minecraft-protocol encryption.js node-minecraft-protocol/src/transforms/encryption.js
node-minecraft-protocol server/login.js node-minecraft-protocol/src/server/login.js
Velocity EncryptionRequestPacket Velocity/proxy/.../packet/EncryptionRequestPacket.java
Velocity EncryptionResponsePacket Velocity/proxy/.../packet/EncryptionResponsePacket.java
Velocity EncryptionUtils Velocity/proxy/.../crypto/EncryptionUtils.java
Velocity JavaVelocityCipher Velocity/native/.../encryption/JavaVelocityCipher.java
Velocity InitialLoginSessionHandler Velocity/proxy/.../client/InitialLoginSessionHandler.java
BungeeCord EncryptionUtil BungeeCord/proxy/.../EncryptionUtil.java
BungeeCord InitialHandler BungeeCord/proxy/.../connection/InitialHandler.java
BungeeCord JavaCipher BungeeCord/native/.../cipher/JavaCipher.java
BungeeCord LengthPrependerAndCompressor BungeeCord/proxy/.../netty/LengthPrependerAndCompressor.java
BungeeCord LoginRequest BungeeCord/protocol/.../packet/LoginRequest.java
BungeeCord LoginSuccess BungeeCord/protocol/.../packet/LoginSuccess.java
BungeeCord EncryptionRequest BungeeCord/protocol/.../packet/EncryptionRequest.java
BungeeCord EncryptionResponse BungeeCord/protocol/.../packet/EncryptionResponse.java
BungeeCord SetCompression BungeeCord/protocol/.../packet/SetCompression.java
minecraft-data protocol.json (all versions) minecraft-data/data/pc/<version>/protocol.json
minecraft-data features.json minecraft-data/data/pc/common/features.json
minecraft.wiki Protocol Encryption https://minecraft.wiki/w/Java_Edition_protocol/Encryption