1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//! Documentation about the PSO2 protocol.
/// Information about NGS encryption.
///
/// ## Encryption handshake
/// ### Client
///
/// Packet encryption starts when the client sends an [`crate::protocol::Packet::EncryptionRequest`] packet.
/// Within this packet the data contains an RSA encrypted data blob with PKCS#1 v1.5 padding.
///
/// Decrypting this blob yields a block of data with the following structure:
///
/// | Offset | Size | Description |
/// |--------|------|-----------------------------------------------|
/// | 0x00 | 0x30 | AES256-CBC encrypted data with PKCS#7 padding |
/// | 0x30 | 0x20 | AES key for the encryption |
///
/// Decrypting the data with the provided key and an IV of
/// `[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]`
/// yields the encryption secret value.
///
/// ### Server
///
/// After parsing the above packet, server sets up the AES256-CBC encryption for all future
/// packets.
///
/// Encryption parameters:
/// - key - received from the client
/// - receive IV, send IV - initially
/// `[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]`,
/// after each packet it is updated to match the last 16 bytes of the packet (note: if the packet
/// is received then the receive IV is updated, if the packet is sent then the send IV is updated).
///
/// After that the server responds with the [`crate::protocol::Packet::EncryptionResponse`] packet
/// which contains the encryption secret AND the client's padding.
///
/// ## Encrypted packet structure
///
/// Every encrypted packet has the following structure:
///
/// | Offset | Size | Description |
/// |--------|----------|---------------------------------------------------|
/// | 0x00 | 0x20 | SHA256 of the header (i.e. from 0x00 to 0x48) |
/// | 0x20 | 0x20 | SHA256 of the data (i.e. from 0x44 to the end) |
/// | 0x40 | 0x4 | Unknown, always `[0x01, 0x00, 0xFF, 0xFF]` |
/// | 0x44 | 0x4 | Packet length (hashes + unknown + length + data) |
/// | 0x48 | Variable | AES256-CBC encrypted data with PKCS#7 padding |
///
/// ## Data compression
///
/// NGS allows the packet data to be compressed. If after decryption the packet starts with `[0x28,
/// 0xB5, 0x2F, 0xFD]`, then this packet is compressed using ZSTD compression. When recompressing
/// set the pledged source size to the full packet size.
///
/// ## Calculating hashes
///
/// 1) Prepare the encrypted packet with zeroed hashes.
/// 2) Calculate the SHA256 of the encrypted packet from 0x44 to the end.
/// 3) Place the resulting hash at 0x20.
/// 4) Calculate the SHA256 of the encrypted packet from the start to 0x48.
/// 5) Place the resulting hash at 0x00.
/// Information about NA encryption.
///
/// ## Encryption handshake
/// ### Client
///
/// Packet encryption starts when the client sends an [`crate::protocol::Packet::EncryptionRequest`] packet.
/// Within this packet the data contains an RSA encrypted data blob with PKCS#1 v1.5 padding.
///
/// Decrypting this blob yields a block of data with the following structure:
///
/// | Offset | Size | Description |
/// |--------|------|-----------------------------------------------|
/// | 0x00 | 0x30 | AES256-CBC encrypted data with PKCS#7 padding |
/// | 0x30 | 0x20 | AES key for the encrypted data |
///
/// Decrypting the data with the provided key and an IV of
/// `[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]`
/// yields the encryption secret value.
///
/// ### Server
///
/// After parsing the above packet, server sets up the AES256-CBC encryption for all future
/// packets.
///
/// Encryption parameters:
/// - key - received from the client
/// - IV - stored in the encrypted packet.
///
/// After that the server responds with the [`crate::protocol::Packet::EncryptionResponse`] packet
/// which contains the encryption secret AND the client's padding.
///
/// ## Encrypted packet structure
///
/// Every encrypted packet has the following structure:
///
/// | Offset | Size | Description |
/// |--------|----------|--------------------------------------------------------|
/// | 0x00 | 0x20 | HMAC-SHA256 of the header (i.e. from 0x00 to 0x58) |
/// | 0x20 | 0x20 | HMAC-SHA256 of the data (i.e. from 0x44 to the end) |
/// | 0x40 | 0x4 | Unknown, always `[0x01, 0x00, 0xFF, 0xFF]` |
/// | 0x44 | 0x4 | Packet length (hashes + unknown + length + data + IV) |
/// | 0x48 | 0x10 | Packet AES IV |
/// | 0x58 | Variable | AES256-CBC encrypted data with PKCS#7 padding |
///
/// ## Calculating hashes
///
/// 1) Prepare the encrypted packet with zeroed hashes.
/// 2) Calculate the HMAC-SHA256 of the encrypted packet from 0x44 to the end with the key
/// `passwordxxxxxxxx`.
/// 3) Place the resulting hash at 0x20.
/// 4) Calculate the HMAC-SHA256 of the encrypted packet from the start to 0x58 with the key
/// `passwordxxxxxxxx`.
/// 5) Place the resulting hash at 0x00.
/// Information about classic (Vita + JP) encryption.
///
/// ## Encryption handshake
/// ### Client
///
/// Packet encryption starts when the client sends an [`crate::protocol::Packet::EncryptionRequest`] packet.
/// Within this packet the data contains an RSA encrypted data blob with PKCS#1 v1.5 padding.
///
/// Decrypting this blob yields a block of data with the following structure:
///
/// | Offset | Size | Description |
/// |--------|------|----------------------------|
/// | 0x00 | 0x10 | RC4 encrypted data |
/// | 0x10 | 0x10 | RC4 key for the encryption |
///
/// Decrypting the data with the provided key yields the encryption secret value.
///
/// ### Server
///
/// After parsing the above packet, server sets up the RC4 encryption for all future packets.
///
/// Encryption parameters:
/// - key - received from the client
///
/// After that the server responds with the [`crate::protocol::Packet::EncryptionResponse`] packet
/// which contains the encryption secret.
///
/// ## Encrypted packet structure
///
/// Because the RC4 encryption is a stream encryption the packet has the same structure as
/// regular packets, but with the keystream applied on top (including length int).
/// Information about packet structure.
///
/// ## Packet structure
///
/// Every packet in the protocol has the following structure:
///
/// | Offset | Size | Description |
/// |--------|----------|------------------------------------------|
/// | 0x0 | 0x4 | Packet length (data + header + size int) |
/// | 0x4 | 0x4 | Packet header |
/// | 0x8 | Variable | Packet data |
///
/// ## Packet header structure [`crate::protocol::PacketHeader`]
///
/// Pre-NGS:
///
/// | Offset | Size | Description |
/// |--------|------|-----------------------------------------|
/// | 0x0 | 0x1 | Packet category (ID) |
/// | 0x1 | 0x1 | Packet ID in the category (SubID) |
/// | 0x2 | 0x1 | Packet flags [`crate::protocol::Flags`] |
/// | 0x3 | 0x1 | Padding (?) |
///
/// NGS:
///
/// | Offset | Size | Description |
/// |--------|------|-----------------------------------------|
/// | 0x0 | 0x1 | Packet flags [`crate::protocol::Flags`] |
/// | 0x1 | 0x1 | Packet category (ID) |
/// | 0x2 | 0x2 | Packet ID in the category (SubID) |
///
/// ## Variable length fields
///
/// Most variable length values are prefixed with their length using encoded [`u32`].
///
/// Values needed for encoding/decoding (varies from packet to packet):
/// - xor - ranges typically from 0x0000 to 0xFFFF
/// - sub - ranges typically from 0x000 to 0x100
///
/// Encoding formula:
/// ```
/// # let xor = 0x100;
/// # let sub = 0x20;
/// # let input = 1;
/// let output = (input + sub) ^ xor;
/// # assert_eq!(output, 0x121);
/// ```
///
/// Decoding formula:
/// ```
/// # let xor = 0x100;
/// # let sub = 0x20;
/// # let input = 0x121;
/// let output = (input ^ xor) - sub;
/// # assert_eq!(output, 1);
/// ```