GJP
The GJP is a string sent in many requests for account authentication. This used in place of simply sending the user's password in the request, which is obviously wildly insecure. There are two variations: GJP (pre-2.2), and GJP2 (2.2+).
Danger
NEVER send your GJP to anyone for any reason. Doing so will compromise your account!
GJP2
GJP2 is a hash usually sent as the gjp2
parameter in requests. It is created using the SHA-1 hash function, and is formatted as a 20-byte, hexadecimal hash value, also known as a message digest.
Warning
While hashing the password with salt is good practice and secure, Rob's implementation isn't for various reasons:
-
Hash salts should be random as to prevent the same input from producing the same output. That is the purpose of a salt. Having the salt as an unchanging, arbitrary string defeats the purpose of having a salt.
-
SHA-1 has long since been considered insecure, and is susceptible to chosen-prefix attacks. Many organizations have recommended it to be replaced with other hash functions, such as SHA-2 or SHA-3.
Thank you, Rob.
Encoding
The hash is created with the user's password and adds mI29fmAnxgTs
as salt.
Here is an example of how one could implement the encoding of the hash into code.
Example
import crypto from "crypto"
let hash = crypto.createHash("sha1")
let password = 'password123' // Replace with the user's password
let salt = "mI29fmAnxgTs"
hash.update(password + salt)
let gjp2 = hash.digest('hex')
console.log(gjp2)
import hashlib
hash = hashlib.sha1()
password = "password123" # Replace with user's password
salt = "mI29fmAnxgTs"
hash.update((password + salt).encode())
gjp2 = hash.hexdigest()
print(gjp2)
Decoding
While encoding a hash is simple enough to do, it cannot be decoded due to the one-way nature of a hash function. This does not mean it is safe to let others see the hash however, as this lets them make requests on your behalf.
GJP
GJP is similar to GJP2, but is outdated and extremely insecure, hence the replacement with a newer version. Unlike GJP2, which uses a one-way hash function, GJP simply uses a combination of XOR encoding and base64 encoding, which can very easily be reversed.
Note
While the Geometry Dash client uses GJP2 for all of the requests, most endpoints still accept the old GJP. It is recommended to avoid using this, however, due to the lack of security GJP has.
Encoding
The GJP is made by taking the user's password, XOR encoding it using a key of 37526
, and then encoding it again with base64.
Here is an example of how one could implement the encoding into code.
Example
import crypto from "crypto"
let hash = crypto.createHash("sha1")
let password = 'password123' // Replace with the user's password
let salt = "mI29fmAnxgTs"
hash.update(password + salt)
let gjp2 = hash.digest('hex')
console.log(gjp2)
import base64
# XOR encryption
def xor_cipher(text, key):
encrypted = ""
for i in range(len(text)):
encrypted += chr(ord(text[i]) ^ ord(key[i % len(key)]))
return encrypted
password = "password123" # Replace with user's password
xor_encoded = xor_cipher(password, "37526")
gjp = base64.b64encode(xor_encoded.encode()).decode()
gjp.replace("+", "-")
gjp.replace("/", "_")
print(gjp)