Let's suppose, I'm creating a simple app to log in to Instagram/Facebook using the Python requests module. I know there is a working code available on the internet to do that but the thing is I want to understand how the guys have reverse-engineered the enc_password (encrypted version of the password needed to login) field needed to login to Instagram.
Here is a sample code I got from instagrapi that generates the enc_pass field when logging in to Instagram.
Below is a sample code for logging in to Instagram using requests that are also extracted from instagrapi project and this works well
All I want to understand is how they reverse-engineer the password_cncrypt() function to create enc_password value?
Is there any starting guide or background I'm missing?
Any help or tips to understand this would be very much appreciated.
Here is a sample code I got from instagrapi that generates the enc_pass field when logging in to Instagram.
from Cryptodome.Cipher import AES, PKCS1_v1_5
from Cryptodome.PublicKey import RSA
from Cryptodome.Random import get_random_bytes
class PasswordMixin:
def password_encrypt(self, password):
publickeyid, publickey = self.password_publickeys()
session_key = get_random_bytes(32)
iv = get_random_bytes(12)
timestamp = str(int(time.time()))
decoded_publickey = base64.b64decode(publickey.encode())
recipient_key = RSA.import_key(decoded_publickey)
cipher_rsa = PKCS1_v1_5.new(recipient_key)
rsa_encrypted = cipher_rsa.encrypt(session_key)
cipher_aes = AES.new(session_key, AES.MODE_GCM, iv)
cipher_aes.update(timestamp.encode())
aes_encrypted, tag = cipher_aes.encrypt_and_digest(password.encode("utf8"))
size_buffer = len(rsa_encrypted).to_bytes(2, byteorder="little")
payload = base64.b64encode(
b"".join(
[
b"\x01",
publickeyid.to_bytes(1, byteorder="big"),
iv,
size_buffer,
rsa_encrypted,
tag,
aes_encrypted,
]
)
)
return f"#PWD_INSTAGRAM:4:{timestamp}:{payload.decode()}"
def password_publickeys(self):
resp = self.public.get("[URL]https://i.instagram.com/api/v1/qe/sync/[/URL]")
publickeyid = int(resp.headers.get("ig-set-password-encryption-key-id"))
publickey = resp.headers.get("ig-set-password-encryption-pub-key")
return publickeyid, publickey
Below is a sample code for logging in to Instagram using requests that are also extracted from instagrapi project and this works well
def login(
self,
username: str,
password: str,
relogin: bool = False,
verification_code: str = "",
) -> bool:
"""
Login
Parameters
----------
username: str
Instagram Username
password: str
Instagram Password
relogin: bool
Whether or not to re login, default False
verification_code: str
2FA verification code
Returns
-------
bool
A boolean value
"""
self.username = username
self.password = password
if relogin:
self.private.cookies.clear()
if self.relogin_attempt > 1:
raise ReloginAttemptExceeded()
self.relogin_attempt += 1
# if self.user_id and self.last_login:
# if time.time() - self.last_login < 60 * 60 * 24:
# return True # already login
if self.user_id and not relogin:
return True # already login
try:
self.pre_login_flow()
except (PleaseWaitFewMinutes, ClientThrottledError):
self.logger.warning("Ignore 429: Continue login")
# The instagram application ignores this error
# and continues to log in (repeat this behavior)
enc_password = self.password_encrypt(password)
data = {
"jazoest": generate_jazoest(self.phone_id),
"country_codes": '[{"country_code":"%d","source":["default"]}]'
% int(self.country_code),
"phone_id": self.phone_id,
"enc_password": enc_password,
"username": username,
"adid": self.advertising_id,
"guid": self.uuid,
"device_id": self.android_device_id,
"google_tokens": "[]",
"login_attempt_count": "0",
}
try:
logged = self.private_request("accounts/login/", data, login=True)
self.authorization_data = self.parse_authorization(
self.last_response.headers.get("ig-set-authorization")
)
except TwoFactorRequired as e:
if not verification_code.strip():
raise TwoFactorRequired(
f"{e} (you did not provide verification_code for login method)"
)
two_factor_identifier = self.last_json.get("two_factor_info", {}).get(
"two_factor_identifier"
)
data = {
"verification_code": verification_code,
"phone_id": self.phone_id,
"_csrftoken": self.token,
"two_factor_identifier": two_factor_identifier,
"username": username,
"trust_this_device": "0",
"guid": self.uuid,
"device_id": self.android_device_id,
"waterfall_id": str(uuid4()),
"verification_method": "3",
}
logged = self.private_request(
"accounts/two_factor_login/", data, login=True
)
self.authorization_data = self.parse_authorization(
self.last_response.headers.get("ig-set-authorization")
)
if logged:
self.login_flow()
self.last_login = time.time()
return True
return False
All I want to understand is how they reverse-engineer the password_cncrypt() function to create enc_password value?
Is there any starting guide or background I'm missing?
Any help or tips to understand this would be very much appreciated.