Closed ozican closed 4 years ago
Ok, I found somethings.. I want to share, maybe we can find the solution together;
I believe this is rc-40 crypto.. Not sure but it looks like rc-40. Anyway, I have public key but I couldn't decrypt it.. public key returns on header; LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1enRZOEZvUlRGRU9mK1RkTGlUdAplN3FIQXY1cmdBMmk5RkQ0YjgzZk1GK3hheW14b0xSdU5KTitRanJ3dnBuSm1LQ0QxNGd3K2w3TGQ0RHkvRHVFCkRiZlpKcmRRWkJIT3drS3RqdDdkNWlhZFdOSjdLczlBM0NNbzB5UktyZFBGU1dsS21lQVJsTlFrVXF0YkNmTzcKT2phY3ZYV2dJcGlqTkdJRVk4UkdzRWJWZmdxSmsrZzhuQWZiT0xjNmEwbTMxckJWZUJ6Z0hkYWExeFNKOGJHcQplbG4zbWh4WDU2cmpTOG5LZGk4MzRZSlNaV3VxUHZmWWUrbEV6Nk5laU1FMEo3dE80eWxmeWlPQ05ycnF3SnJnCjBXWTFEeDd4MHlZajdrN1NkUWVLVUVaZ3FjNUFuVitjNUQ2SjJTSTlGMnNoZWxGNWVvZjJOYkl2TmFNakpSRDgKb1FJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
It's evp_aes_256_gcm encrypted.
thank you very much, I am investigating it now... I never hear it before ๐
Hey guys, did you found the solution what need to do with it?
This is for the web-version. But it's similar. But your enc-version is here 6, in the app, it's 4.
@Nerixyz how much similar? Is only differences about version?
They both encrypt the aes-key with rsa and put it into a buffer. ~I can paste my current code here later.~
This is my take. It doesn't work, bu I know the keyId is at least right. This is then sent to enc_password: `#PWD_INSTAGRAM:4:${time}:${encrypted}`,
function encryptPassword(password: string): { time: string, encrypted: string } {
const plainKey = Buffer.from(ig.state.passwordEncryptionPubKey, 'base64').toString();
const randKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(12);
const resEncrypted = crypto.publicEncrypt(plainKey, randKey);
const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
const time = Math.floor(Date.now() / 1000).toString();
cipher.setAAD(Buffer.from(time));
const aesEncrypted = concat(cipher.update(password, 'utf8'), cipher.final());
const sizeBuffer = Buffer.alloc(2, 0);
sizeBuffer.writeInt16LE(resEncrypted.byteLength, 0);
const authTag = cipher.getAuthTag();
return {
time,
encrypted: concat(
Buffer.from([1, ig.state.passwordEncryptionKeyId]),
iv,
sizeBuffer,
resEncrypted, aesEncrypted, authTag)
.toString('base64'),
};
}
@Nerixyz thank you for your response, it's very explanatory... I try to solve, I hope we can...
I'm also stuck on it, did anyone find a way to generate the enc_password
?
not me unfortunately.. that beats me
password: adminka55 enc_password: #PWD_INSTAGRAM_BROWSER:6:1573829509755:encodeBase64(encrypt("AES-GCM-256","adminka55","1573829509755"))
is that working? @Frake7 but this is web right? and there is no pub_key?
This is my take. It doesn't work, bu I know the keyId is at least right. This is then sent to
enc_password: `#PWD_INSTAGRAM:4:${time}:${encrypted}`,
function encryptPassword(password: string): { time: string, encrypted: string } { const plainKey = Buffer.from(ig.state.passwordEncryptionPubKey, 'base64').toString(); const randKey = crypto.randomBytes(32); const iv = crypto.randomBytes(12); const resEncrypted = crypto.publicEncrypt(plainKey, randKey); const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv); const time = Math.floor(Date.now() / 1000).toString(); cipher.setAAD(Buffer.from(time)); const aesEncrypted = concat(cipher.update(password, 'utf8'), cipher.final()); const sizeBuffer = Buffer.alloc(2, 0); sizeBuffer.writeInt16LE(resEncrypted.byteLength, 0); const authTag = cipher.getAuthTag(); return { time, encrypted: concat( Buffer.from([1, ig.state.passwordEncryptionKeyId]), iv, sizeBuffer, resEncrypted, aesEncrypted, authTag) .toString('base64'), }; }
I use this for now.... I made some changes for node.js, I don't know why you said it is not working. If you can explain I can try to fix it.
It's able to encrypt but the request fails.
It works on me, I only changed some small things for node.js. Thank you very much by the way @Nerixyz I am very happy about it.
It works on me, I only changed some small things for node.js. Thank you very much by the way @Nerixyz I am very happy about it.
Could you paste your code here? I've also used node for this.
@Nerixyz here you are
const crypto = require('crypto');
const getEncPassword = (password, pubKey, keyID) => {
const plainKey = Buffer.from(pubKey, 'base64').toString();
const randKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(12);
const resEncrypted = crypto.publicEncrypt(plainKey, randKey);
const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
const time = Math.floor(Date.now() / 1000).toString();
cipher.setAAD(Buffer.from(time));
const aesEncrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
const sizeBuffer = Buffer.alloc(2, 0);
sizeBuffer.writeInt16LE(resEncrypted.byteLength, 0);
const authTag = cipher.getAuthTag();
const pass = Buffer.concat(
[Buffer.from([1, keyID]),
iv,
sizeBuffer,
resEncrypted, aesEncrypted, authTag])
.toString('base64')
console.log(`#PWD_INSTAGRAM:4:${time}:${pass}`)
}
@Nerixyz @ozican why do you think that working correctly? If we capture requests and set up values like there (I mean time, keys) - enc_password must be the same. But it's not the same
@Keln54 It will never be. As you can see, a RANDOM key is created that is then encrypted with the pkey.
@Nerixyz so, why do you think they must be random? Where you get this information?) I think not, because - how do instagram check the correct of this value? They must take time and pass - then check enc_password sending by your side with enc_password they get.
Typically then messages are not encrypted directly with such keys but are instead encrypted using a symmetric "session" key. This key is itself then encrypted using the public key.
https://wiki.openssl.org/index.php/EVP_Asymmetric_Encryption_and_Decryption_of_an_Envelope
sorry for my low knowledge, what do you think? @Nerixyz is everything ok now? I mean, is that encrypt method is right?
Because I think, if you put same values, crypted data can be different with this crypto method. am I right or not?
The aes-gcm is right and also the public-key encryption is right. Only the order of concatenation and maybe some small settings are wrong.
OK great because I think I can investigate more about it.
@Nerixyz here you are
const crypto = require('crypto'); const getEncPassword = (password, pubKey, keyID) => { const plainKey = Buffer.from(pubKey, 'base64').toString(); const randKey = crypto.randomBytes(32); const iv = crypto.randomBytes(12); const resEncrypted = crypto.publicEncrypt(plainKey, randKey); const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv); const time = Math.floor(Date.now() / 1000).toString(); cipher.setAAD(Buffer.from(time)); const aesEncrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]); const sizeBuffer = Buffer.alloc(2, 0); sizeBuffer.writeInt16LE(resEncrypted.byteLength, 0); const authTag = cipher.getAuthTag(); const pass = Buffer.concat( [Buffer.from([1, keyID]), iv, sizeBuffer, resEncrypted, aesEncrypted, authTag]) .toString('base64') console.log(`#PWD_INSTAGRAM:4:${time}:${pass}`) }
does this work for you?
I have an error with "const resEncrypted = crypto.publicEncrypt(plainKey, randKey);" - error:0906D06C:PEM routines:PEM_read_bio:no start line
I have an error with "const resEncrypted = crypto.publicEncrypt(plainKey, randKey);" - error:0906D06C:PEM routines:PEM_read_bio:no start line
Is your public key from ig.state.passwordEncryptionPubKey
?
does this work for you?
This works. But the request using this password fails with "Oops, an error occurred.".
does this work for you?
This works. But the request using this password fails with "Oops, an error occurred.".
same thing =( Is there any solution?
does this work for you?
This works. But the request using this password fails with "Oops, an error occurred.".
strange because I don't get that error. I successfully login or create
@ozican How so you log in then?
@Nerixyz I might have the solution or most of it. Ping me if you want to share ideas (email on profile)
Regards
@crouchingtiger Hello. Yes I get my keyID and pubKey from header. I am not on my main computer now but it is like; ig-set-keyId
and รฌg-set-pubKey`
by the way for some test I can give to you a rest API for test it (only for @Nerixyz and @crouchingtiger and @mgp25 ) (because of server is not enough powerfull)
just email me if you want.. ozandikbas@gmail.com
I have solved it already, I am not with the computer but if you send me a hex dump via email I can guide you for the implementation
regards
Don't RSA encrypt the public key as shown in the node.js code above.
The public key isn't encrypted. The key used for the AES-GCM encryption is encrypted here. This is in fact the result you get in the ek
buffer.
The "updated" code loks like this:
const randKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(12);
const rsaEncrypted = crypto.publicEncrypt(Buffer.from(ig.state.passwordEncryptionPubKey, 'base64').toString(), randKey);
const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
const time = Math.floor(Date.now() / 1000).toString();
const aesEncrypted = concat(cipher.setAAD(Buffer.from(time)).update(password), cipher.final());
const authTag = cipher.getAuthTag();
const sizeBuffer = Buffer.alloc(2, 0);
sizeBuffer.writeInt16LE(rsaEncrypted.byteLength, 0);
return {
time,
encrypted: concat(
Buffer.from([1, ig.state.passwordEncryptionKeyId]),
iv,
sizeBuffer,
rsaEncrypted,
authTag,
aesEncrypted)
.toString('base64'),
};
There's still something wrong.
A gift for you people:
public static function encryptPassword(
$password,
$publicKeyId,
$publicKey)
{
$key = openssl_random_pseudo_bytes(32);
$iv = openssl_random_pseudo_bytes(12);
$time = time();
openssl_public_encrypt($key ,$encryptedAesKey, base64_decode($publicKey));
$encrypted = openssl_encrypt($password, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, strval($time));
$payload = base64_encode("\x01" | pack('n', intval($publicKeyId)) . $iv . pack('s', strlen($encryptedAesKey)) . $encryptedAesKey . $tag . $encrypted);
return sprintf('#PWD_INSTAGRAM:4:%s:%s', $time, $payload);
}
IG Android default public key (ID: 41):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvcu1KMDR1vzuBr9iYKW8
KWmhT8CVUBRkchiO8861H7zIOYRwkQrkeHA+0mkBo3Ly1PiLXDkbKQZyeqZbspke
4e7WgFNwT23jHfRMV/cNPxjPEy4kxNEbzLET6GlWepGdXFhzHfnS1PinGQzj0ZOU
ZM3pQjgGRL9fAf8brt1ewhQ5XtpvKFdPyQq5BkeFEDKoInDsC/yKDWRAx2twgPFr
CYUzAB8/yXuL30ErTHT79bt3yTnv1fRtE19tROIlBuqruwSBk9gGq/LuvSECgsl5
z4VcpHXhgZt6MhrAj6y9vAAxO2RVrt0Mq4OY4HgyYz9Wlr1vAxXXGAAYIvrhAYLP
7QIDAQAB
-----END PUBLIC KEY-----
Public Key returned on API responses (ID: 205):
const IG_LOGIN_ANDROID_PUBLIC_KEY= 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1enRZOEZvUlRGRU9mK1RkTGlUdAplN3FIQXY1cmdBMmk5RkQ0YjgzZk1GK3hheW14b0xSdU5KTitRanJ3dnBuSm1LQ0QxNGd3K2w3TGQ0RHkvRHVFCkRiZlpKcmRRWkJIT3drS3RqdDdkNWlhZFdOSjdLczlBM0NNbzB5UktyZFBGU1dsS21lQVJsTlFrVXF0YkNmTzcKT2phY3ZYV2dJcGlqTkdJRVk4UkdzRWJWZmdxSmsrZzhuQWZiT0xjNmEwbTMxckJWZUJ6Z0hkYWExeFNKOGJHcQplbG4zbWh4WDU2cmpTOG5LZGk4MzRZSlNaV3VxUHZmWWUrbEV6Nk5laU1FMEo3dE80eWxmeWlPQ05ycnF3SnJnCjBXWTFEeDd4MHlZajdrN1NkUWVLVUVaZ3FjNUFuVitjNUQ2SjJTSTlGMnNoZWxGNWVvZjJOYkl2TmFNakpSRDgKb1FJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==';
Format:
Sample (Hex representation):
01 **(ID: 0x01)**
cd **(Pub. ID: 205)**
3d5c3a5c044d5c07f94ea2f5 **(IV)**
0001 **(256 RSA length little endian)**
47e81a1588e7d650b512d56e992ef5b1ce24050d64eb33626cdb695edb595c2b73f0205683ef9f84a6ebceb6e5f2384bd094caa47b3d8912bda5ddb03f7c2668501414639edc3fd9e47ddd6ab1cead3900699c7625dc35a6e85b696d9a4585a142fc7d99df6cdb685d555567a9fb69816996e776509f80ff360556c4d2b2819bbdd048ca3b6d30a70d40db28b40a3de6903ebfdf6adfd3d1674ba0dc1ec6adf39ac95fadece4e88a7b6ac598e8c58b639aa75ae27ee406caee1155bbc817e7014d24f69592715b63257124a067a326d0db7794540543c95492255438c280b6768662983983b5e82e67bc5371de391ce00c2e8c864e97a9aa9612acf977a19abd **RSA Enc. Key**
f7364edeba87bc2e3dd73c31f51e9898 **AES GCM TAG**
b92c412352e9d519bc2733 **Enc. PW**
Happy new year! ๐
hahah this is my first and best new year gift on this year! Thank you man...! ๐
As a test, I decided to deliberately mismatch
key-id
and validpub-key
values. There's at least 3 pub-keys/ids that are available/public - default/android fallback (41), android (205), and web (245). If your envelope is correct, but the versions mismatch, then you'll getHTTP 400
responses:
Do you happen to have the Public Key for the web (245) version? All I can find in the headers and code is an hex string ("f5a1fdb4e2e032e5d3b42c3350d69918eebdb640e2f9cc0fe1fc55cd7800cf30") which if translated to base64 gives "9aH9tOLgMuXTtCwzUNaZGO69tkDi+cwP4fxVzXgAzzA=" which is not a public key.
OMG its @mgp25! Maybe someday you'll unblock me ๐
Do someone has solved this using python?
pls someone help, I see a solution, but how to implement it in c# or c++ or java or python ?
Don't RSA encrypt the public key as shown in the node.js code above.
The public key isn't encrypted. The key used for the AES-GCM encryption is encrypted here. This is in fact the result you get in the
ek
buffer.The "updated" code loks like this:
const randKey = crypto.randomBytes(32); const iv = crypto.randomBytes(12); const rsaEncrypted = crypto.publicEncrypt(Buffer.from(ig.state.passwordEncryptionPubKey, 'base64').toString(), randKey); const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv); const time = Math.floor(Date.now() / 1000).toString(); const aesEncrypted = concat(cipher.setAAD(Buffer.from(time)).update(password), cipher.final()); const authTag = cipher.getAuthTag(); const sizeBuffer = Buffer.alloc(2, 0); sizeBuffer.writeInt16LE(rsaEncrypted.byteLength, 0); return { time, encrypted: concat( Buffer.from([1, ig.state.passwordEncryptionKeyId]), iv, sizeBuffer, rsaEncrypted, authTag, aesEncrypted) .toString('base64'), };
There's still something wrong.
The only fix needed for Node.js was to set the right RSA-Padding. The updated code can be found here.
Looking for a python port of the nodejs that @Killer-Awesome-Phantom posted. I attempted it (https://pastebin.com/raw/DURQVhTn) however I messed up somewhere.
do you know why this code don't work ? return
"{"message": "There was an error with your request. Please try again.", "status": "fail"}"
ig-set-password-encryption-web-key-id: 245
ig-set-password-encryption-web-pub-key: f5a1fdb4e2e032e5d3b42c3350d69918eebdb640e2f9cc0fe1fc55cd7800cf30
and how i can convert web version hex to public key format accept in php ?
<?php
$Username = 'myuser';
$password='mypass';
const IG_LOGIN_ANDROID_PUBLIC_KEY= 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF1enRZOEZvUlRGRU9mK1RkTGlUdAplN3FIQXY1cmdBMmk5RkQ0YjgzZk1GK3hheW14b0xSdU5KTitRanJ3dnBuSm1LQ0QxNGd3K2w3TGQ0RHkvRHVFCkRiZlpKcmRRWkJIT3drS3RqdDdkNWlhZFdOSjdLczlBM0NNbzB5UktyZFBGU1dsS21lQVJsTlFrVXF0YkNmTzcKT2phY3ZYV2dJcGlqTkdJRVk4UkdzRWJWZmdxSmsrZzhuQWZiT0xjNmEwbTMxckJWZUJ6Z0hkYWExeFNKOGJHcQplbG4zbWh4WDU2cmpTOG5LZGk4MzRZSlNaV3VxUHZmWWUrbEV6Nk5laU1FMEo3dE80eWxmeWlPQ05ycnF3SnJnCjBXWTFEeDd4MHlZajdrN1NkUWVLVUVaZ3FjNUFuVitjNUQ2SjJTSTlGMnNoZWxGNWVvZjJOYkl2TmFNakpSRDgKb1FJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==';
function encryptPassword(
$password,
$publicKeyId,
$publicKey)
{
$key = openssl_random_pseudo_bytes(32);
$iv = openssl_random_pseudo_bytes(12);
$time = time();
openssl_public_encrypt($key ,$encryptedAesKey, base64_decode($publicKey));
$encrypted = openssl_encrypt($password, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, strval($time));
$payload = base64_encode("\x01" | pack('n', intval($publicKeyId)) . $iv . pack('s', strlen($encryptedAesKey)) . $encryptedAesKey . $tag . $encrypted);
return sprintf('#PWD_INSTAGRAM_BROWSER:6:%s:%s', $time, $payload);
}
$enc= encryptPassword($password,245,IG_LOGIN_ANDROID_PUBLIC_KEY);
$vars='username='.$Username.'&password='.$password.'&enc_password='.urlencode($enc).'&queryParams=%7B%7D&optIntoOneTap=false';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://www.instagram.com/accounts/login/ajax/");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$vars); //Post Fields
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$headers = [
'User-Agent: Mozilla/5.0 (Linux; Android 10; Z832 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Mobile Safari/537.36' ,
'Accept: */*' ,
'Accept-Language: en-US,en;q=0.5' ,
'X-CSRFToken: 62Fvm60ukhKaYnxdS9sOKrANwHu1SqXp' ,
'X-Instagram-AJAX: 138daaa28c25' ,
'X-IG-App-ID: 1217981644879628' ,
'X-IG-WWW-Claim: 0' ,
'Content-Type: application/x-www-form-urlencoded' ,
'X-Requested-With: XMLHttpRequest' ,
'Origin: https://www.instagram.com' ,
'Connection: keep-alive' ,
'Referer: https://www.instagram.com/accounts/login/' ,
'Cookie: ig_cb=1; ig_did=2E232D1A-7FE5-4412-9D9B-0AC072FD937C; csrftoken=62Fvm60ukhKaYnxdS9sOKrANwHu1SqXp; rur=VLL; mid=Xjg6kgABAAHOs8f6YUYvLc7XDa_S' ,
'TE: Trailers'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$server_output = curl_exec ($ch);
curl_close ($ch);
var_dump( $server_output) ;
?>
const IG_LOGIN_ANDROID_PUBLIC_KEY= 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQk
https://github.com/dilame/instagram-private-api/issues/1010#issuecomment-569759860
do you know why this code don't work ? return
The browser encryption is different. You have to use your browser to "reverse" that.
As this issue-thread isn't an issue for the library anymore, it will be closed. However, you'll still be able to discuss on the topic.
On Tue, Feb 18, 2020 at 8:28 PM dentrav12 notifications@github.com wrote:
@PappaPaj https://github.com/PappaPaj I really sorry for this but have you been successful with Python implementation?
I have edited and finished the implementation in python however it still doesnโt seem to work as I get an error from Instagram.
Question
Hello people, I got a new header value. I just wanna ask, have you ever see that and do you know how can I generate it? That's my value. "enc_password":"#PWD_INSTAGRAM:4:1575910572:Ac09XDpcBE1cB/lOovUAAUfoGhWI59ZQtRLVbpku9bHOJAUNZOszYmzbaV7bWVwrc/AgVoPvn4Sm68625fI4S9CUyqR7PYkSvaXdsD98JmhQFBRjntw/2eR93Wqxzq05AGmcdiXcNaboW2ltmkWFoUL8fZnfbNtoXVVVZ6n7aYFplud2UJ+A/zYFVsTSsoGbvdBIyjttMKcNQNsotAo95pA+v99q39PRZ0ug3B7GrfOayV+t7OTointqxZjoxYtjmqda4n7kBsruEVW7yBfnAU0k9pWScVtjJXEkoGejJtDbd5RUBUPJVJIlVDjCgLZ2hmKYOYO16C5nvFNx3jkc4AwujIZOl6mqlhKs+Xehmr33Nk7euoe8Lj3XPDH1HpiYuSxBI1Lp1Rm8JzM="