tgalal / yowsup

The WhatsApp lib
GNU General Public License v3.0
7.08k stars 2.23k forks source link

Backup Token #3123

Open galdudi opened 2 years ago

galdudi commented 2 years ago

I'm trying to register (request sms) with my number and got an error:

{"login":"xxxxxxxxxxxxx","param":"backup_token","reason":"bad_param","status":"fail"}

It was working fine until last week

mrhghhgh commented 2 years ago

I got this error too, with both sms and call request.

yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead yowsup.common.http.warequest - b'{"login":"xxxxxxxxxxxx","param":"backup_token","reason":"bad_param","status":"fail"}\n' status: b'fail' reason: b'bad_param' param: b'backup_token' login: b'xxxxxxxxxxxx'

YazinAlhamdi commented 2 years ago

Same a problem for me!

GM12Tick commented 2 years ago

This is a new parameter added lately and is required.

acharyadev12 commented 2 years ago

I have same problem... Is there any solution?

lauriolasw commented 2 years ago

Same here

yowsup-cli v3.2.1 yowsup v3.3.0 consonance v0.1.5 dissononce v0.34.3 python-axolotl v0.2.2 cryptography v2.5 protobuf v3.0.0

{"login":"xxx","param":"backup_token","reason":"bad_param","status":"fail"}

SamuelScheit commented 2 years ago

I'm working on a solution

SamuelScheit commented 2 years ago

Alright after setting up the reverse engineering environment I was able to debug the WhatsApp application and decompiled the smali source code to java for easier readability. (I'll later publish a setup guide for other contributors) The backup_token is generated the first time the user registers and then saved in a local backup_token file.

I've written a guide on how to generate this backup_token with JS examples, someone else need to implement them in python and create a PR for this library. I couldn't test the example scripts against WhatsApp, so if something fails please let me know.

  1. Generate the base string by joining the result of the following two parts into a single string

    1. Constant: A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES (Extracted from class X.0BF.A0L)

      const constant =
          "A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES";
      let backup_token_constant = "";
      
      for (let i = 0; i < constant.length; i++) {
          backup_token_constant += String.fromCharCode(constant.charCodeAt(i) ^ 18);
      }
      return backup_token_constant;

      Result: S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA

    2. The last 4 digits of the users phone number

      "11234567890".slice(-4);

      Result: 7890

  2. Convert the base string into a buffer

    const backup_token_constant =
        "S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA";
    const last_digits = "7890";
    
    const base = backup_token_constant + last_digits;
    
    const buffer = Buffer.from(base);

    Result: <Buffer 53 16 0f 52 03 0a 44 c2 83 10 c2 82 c2 9a c2 8d c2 8c 46 3a 21 69 29 57 41 37 38 39 30> or as decimal binary:[83, 22, 15, 82, 3, 10, 68, 131, 16, 130, 154, 141, 140, 70, 58, 33, 105, 41, 87, 65, 55, 56, 57, 48]

  3. Generate a 16 bytes long sha1 key with 16 iterations and a 4 bytes long salt using the Password-Based Key Derivation Function 2 (PBKDF2) based on the previous buffer and saltA value.

    WhatsApp on Android uses the javax.crypto.SecretKeyFactory with PBKDF2WithHmacSHA1And8BIT (Extracted from class X.0BA.A06()). In Java you have to use PBKDF2WithHmacSHA1 and a keylength of 128.

    The NodeJS equivalent crypto.pbkdf2Sync() can be used to generate the key:

    const crypto = require("crypto");
    
    // buffer from step 2
    const salt = crypto.randomBytes(4); // <Buffer ee 1b 75 2e>
    const iterations = 16;
    const keylength = 16; // in java is the keylen 128
    const key = crypto.pbkdf2Sync(buffer, salt, iterations, keylength, "sha1");
  4. Generate an aes-128-ofb cipher based on the previous sha1 key and 16 bytes long IV and random 20 bytes buffer as input

    const crypto = require("crypto");
    
    const IV = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv('aes-128-ofb', key, IV);
    const encrypted = cipher.update(crypto.randomBytes(20))
  5. Construct the final backup_token by combining [0, 2], salt, IV, encrypted

    Buffer.concat([Buffer.from([0, 2]), salt, IV, encrypted])

Final Script

const crypto = require("crypto");

const constant = "A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES";
let backup_token_constant = "";

for (let i = 0; i < constant.length; i++) {
    backup_token_constant += String.fromCharCode(constant.charCodeAt(i) ^ 18);
}
const last_digits = "11234567890".slice(-4);

const base = backup_token_constant + last_digits;
const buffer = Buffer.from(base);

const salt = crypto.randomBytes(4); 
const iterations = 16;
const keylength = 16; // in java is the keylen 128
const key = crypto.pbkdf2Sync(buffer, salt, iterations, keylength, "sha1");
const IV = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-128-ofb', key, IV);
const encrypted = cipher.update(crypto.randomBytes(20))

const backup_token = Buffer.concat([Buffer.from([0, 2]), salt, IV, encrypted])
console.log(backup_token.toString("hex"))

Example backup token: 0002cf3550ec083dd5b7618b54746c9c8dfaabbd8e1dd21d1fb8e942ce3ab81c4a0ff1e03e8c8fb98e5a

leotrubach commented 2 years ago
import secrets
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import OFB
from cryptography.hazmat.primitives.ciphers.base import Cipher

BACKUP_TOKEN_CONSTANT = b"S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA"
BACKUP_TOKEN_HEADER = b'\x00\x02'

def get_backup_token(phone: str):
    tail = phone[-4:].encode("ascii")
    base = BACKUP_TOKEN_CONSTANT + tail
    salt = secrets.token_bytes(4)
    key = PBKDF2HMAC(
        algorithm=hashes.SHA1(),
        length=16,
        salt=salt,
        iterations=16
    ).derive(base)
    iv = secrets.token_bytes(16)
    cipher = Cipher(AES(key), mode=OFB(iv))
    encryptor = cipher.encryptor()
    payload = secrets.token_bytes(20)
    encrypted = encryptor.update(payload)
    result = b"".join([BACKUP_TOKEN_HEADER, salt, iv, encrypted])
    return result.hex()

Converted to python, checked on non-random salt, IV and payload (random 20 bytes)

salt = [0, 1, 2, 3]
IV = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
payload = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

The results in JS code and Python code match ('000200010203000102030405060708090a0b0c0d0e0f67fa2d28f830f0333d868a43d35da3e75118141a') starting working on PR

leotrubach commented 2 years ago

@Flam3rboy do we know how backup token is passed? I tried base64 and hex and insert it as ,"backup_token" but it didn't work. Are there frameworks in java or js like yowsup where it was implemented?

assegaf commented 2 years ago

more effort converting java to pyton, we already pissed off converting smali to java ...

SamuelScheit commented 2 years ago

@leotrubach I'm currently investigating how the backup token is passed to WhatsApp and will let you know when I find anything 👍

SamuelScheit commented 2 years ago

When the registration request is constructed the following parameters are passed to the JniBridge

image

The backup_token is probably named something else, because I can't find any property named backup_token

leotrubach commented 2 years ago

Okay, i decoded some parts of hashmap, so probably backup token isn't in that hashmap, which means it could be one of v6 or v7

offline_ab: '{"exposure":[],"metrics":{}}'
network_radio_type: seems like it is now 3 bytes - '111'
hasinrc - '1'
sim_operator_name: "T-Mobile"
pid: '3744'
sim_state: '5'
token: 'HQL+1iodePFzduaN3VrQUIh4vks=' which is bytes[20] '1d 02 fe d6 2a 1d 78 f1 73 76 e6 8d dd 5a d0 50 88 78 be 4b' or [29, 2, 254, 214, 42, 29, 120, 241, 115, 118, 230, 141, 221, 90, 208, 80, 136, 120, 190, 75]
rc: '0'
client_metrics: '{"attempts":11,"was_activated_from_stub":false}'
mistyped: '7'
simnum: '0'
read_phone_permission_granted: '0'
network_operator_name: 'Android"
mrhghhgh commented 2 years ago

The backup_token is generated the first time the user registers and then saved in a local backup_token file.

Where is the location in project and the format that we should save this file?

SamuelScheit commented 2 years ago

@mrhghhgh It is saved as binary in /data/data/com.whatsapp/files/backup_token

mrhghhgh commented 2 years ago

@mrhghhgh It is saved as binary in /data/data/com.whatsapp/files/backup_token

Thanks, but is this an android directory? I was using yowsup in desktop ubuntu before this error be appeared and in yowsup project folder or ubuntu there isn't any directory like this. Please help me again

galdudi commented 2 years ago

The real question is not where it saved, but how it is sent during registration?

guy111a commented 2 years ago

so is there a solution or this is not usable any more ?

brunoaduarte commented 2 years ago

so is there a solution or this is not usable any more ?

I'm wondering the same

assegaf commented 2 years ago

well its easy if you can follow how its generated and sent (encoded) in apk file, use jadx-gui to find out

guy111a commented 2 years ago

Thank you .. if I could understand what to do I would not have asked …

Guy A

On 25 Feb 2022, at 3:00, assegaf @.***> wrote:

 well its easy if you can follow how its generated and sent (encoded) in apk file, use jadx-gui to find out

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.

assegaf commented 2 years ago

register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup

guy111a commented 2 years ago

Thank you.

I don’t have android. Can it be done by computer ( windows / linux ) or by iphone ?

Guy A

On 25 Feb 2022, at 12:58, assegaf @.***> wrote:

 register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.

guy111a commented 2 years ago

Can any one just add the line how to call the function? What fields should be passes.

Guy A

On 25 Feb 2022, at 12:58, assegaf @.***> wrote:

 register using real android phone and find all data in /data/data/com.whatsapp to be used by yowsyup

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.

Whomakes commented 2 years ago

Has anyone found a fix?

assegaf commented 2 years ago

its common encoding parameter aes hash SecretKeySpec secretKeySpec = new SecretKeySpec(new SecretKeySpec(C015602t.m20338A06(obj.getBytes(), A0D, 16, 128).getEncoded(), "AES").getEncoded(), "AES/OFB/NoPadding"); etc etc ..

but the main problem its using Android BackupAgentHelper mechanism, which is upload your backup_token to google cloud. so basically if you register and able to generate the hash, its a trap isnt in cloud there is no your backup_token anywhere.

galdudi commented 2 years ago

Has anyone know where on android client saves: expid, fdid, id ?

dhirennjaypal commented 2 years ago

has anyone solved this ? i am trying this for first time.

guy111a commented 2 years ago

i will be happy if you add it here ...

On Thu, Mar 3, 2022 at 10:33 PM varknov @.***> wrote:

i found the way and how is sent, registration working. interested ones can contact me: @.***

— Reply to this email directly, view it on GitHub https://github.com/tgalal/yowsup/issues/3123#issuecomment-1058462799, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJTXH2TYTKCVDPSSC33QOW3U6EO2ZANCNFSM5OIRWN5Q . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

--

~Guy

guy111a commented 2 years ago

Ya .. well. Good luck with btc lol ..

Guy A

On 3 Mar 2022, at 22:33, varknov @.***> wrote:

 i found the way and how is sent, registration working. interested ones can contact me: @.***

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you commented.

saharh commented 2 years ago

I believe the parameters encoding are taking part in the native lib (libwhatsapp.so), so while we have a good idea of the data sent to the native lib (See here), in order to understand how the parameter is encoded in the HTTP request we need to debug the native lib, which is challenging.

If anyone already found the solution, or got any further progress, it would be greatly appreciated if you could share it!

gradol commented 2 years ago

I tried to research the android app first and it really changed a lot of the registration options. However, I tried to research the iOS application and, to my surprise, all registration request parameters remained the same. The only difference is in the implementation of token generation. I made a pull request: https://github.com/tgalal/yowsup/pull/3127 . The only important condition is to use information about the iOS device when making requests via HTTP or XMPP.

guy111a commented 2 years ago

thank you for this information.

can you please explain how to find this information in ios and how to use it ?

thank you

On Fri, Mar 11, 2022 at 9:10 PM gradol @.***> wrote:

I tried to research the android app first and it really changed a lot of the registration options. However, I tried to research the iOS application and, to my surprise, all registration request parameters remained the same. The only difference is in the implementation of token generation. I made a pull request: #3127 https://github.com/tgalal/yowsup/pull/3127 . The only important condition is to use information about the iOS device when making requests via HTTP or XMPP.

— Reply to this email directly, view it on GitHub https://github.com/tgalal/yowsup/issues/3123#issuecomment-1065411258, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJTXH2VA7FDURP2C6UQKU7LU7OLANANCNFSM5OIRWN5Q . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

--

~Guy

binbruce commented 2 years ago

Excuse me Can you tell me how to get the token? I want to replace the device information and token. thanks you so much!

I tried to research the android app first and it really changed a lot of the registration options. However, I tried to research the iOS application and, to my surprise, all registration request parameters remained the same. The only difference is in the implementation of token generation. I made a pull request: #3127 . The only important condition is to use information about the iOS device when making requests via HTTP or XMPP.

gradol commented 2 years ago

I used Frida + jailbroken idevice and IDA. Here sample of code for TOKEN str generation

from binascii import unhexlify 
from binascii import hexlify
from Crypto.Cipher import AES

## Got from WaFoundation framework from function WABuildHash()
wa_build_str = "45e25b6ddecace8d01828dd00bd4ff64".encode() 
## Got data from value which used before call function WABuildHash in WhatsApp 
enc_data = unhexlify(b"6268c9cc61898358c657d1d71932ef2ee7b24109b9668c1962be7d8c1f5ec7f63e9158315f7d6350176d2425894fc6e7") 
key = "landscape".encode() + b"\x00"*7;
data = AES.new(key, AES.MODE_ECB).decrypt(enc_data)
data = data[0:0x28]
token_str = data + wa_build_str
print(token_str.decode())

Output 0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM45e25b6ddecace8d01828dd00bd4ff64

mrjoebudi commented 2 years ago

My advice for Yowsup users is to read the reply comments often, there I found a successful way to overcome BAD PARAM, BACKUP_TOKEN Error,

`C:\wapy>py yowsup-cli registration --requestcode sms --config-phone 62857xxxxxxxx --config-cc 62 --config-mcc 510 --config-mnc 01 E 2022-03-15 02:58:18,171 yowsup.config.manager - Could not find a config for profile=62857xxxxxxxx, paths checked: 62857xxxxxxxx:C:\Users\kampret\AppData\Local\yowsup\yowsup\62857xxxxxxxx\config.yo:C:\Users\kampret\AppData\Local\yowsup\yowsup\62857xxxxxxxx\config.json yowsup-cli v3.2.1 yowsup v3.3.0

Copyright (c) 2012-2019 Tarek Galal http://www.openwhatsapp.org

This software is provided free of charge. Copying and redistribution is encouraged.

If you appreciate this software and you would like to support future development please consider donating: http://openwhatsapp.org/yowsup/donate

W 2022-03-15 02:58:18,263 yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead I 2022-03-15 02:58:20,990 yowsup.common.http.warequest - b'{"flash_type":0,"length":6,"login":"62857xxxxxxxx","method":"sms","notify_after":86400,"retry_after":64,"sms_wait":64,"status":"sent","voice_wait":64}\n' status: b'sent' length: 6 method: b'sms' retry_after: 64 login: b'62857xxxxxxxx' sms_wait: 64 voice_wait: 64

C:\wapy>py yowsup-cli registration --register 509944 --config-phone 62857xxxxxxxx yowsup-cli v3.2.1 yowsup v3.3.0

Copyright (c) 2012-2019 Tarek Galal http://www.openwhatsapp.org

This software is provided free of charge. Copying and redistribution is encouraged.

If you appreciate this software and you would like to support future development please consider donating: http://openwhatsapp.org/yowsup/donate

W 2022-03-15 02:58:44,139 yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead I 2022-03-15 02:58:48,638 yowsup.common.http.warequest - b'{"login":"62857xxxxxxxx","security_code_set":false,"status":"ok","type":"new"}\n' { "version": 1, "cc": "62", "client_static_keypair": "2CmcxWCrNcHAKLg4CAvXHBJuRwnbexqTzMP5Nn2CuVGPWa7MgmhEx2mxxxxxxxxxx==", "expid": "l+NPZEUaTA2rxxxxxxxxxx==", "fdid": "61e71fe1-xxxx-xxxx-xxxx-7e58437xxxxx", "id": "IyH4caFFW7tyQb5VTIpx4ixxxxx=", "login": "62857xxxxxxxx", "mcc": "510", "mnc": "01", "phone": "62857xxxxxxxx", "sim_mcc": "000", "sim_mnc": "000" } status: b'ok' login: b'62857xxxxxxxx' type: b'new'`

Whatsapp-Protocol commented 2 years ago

image

Whomakes commented 2 years ago

I used Frida + jailbroken idevice and IDA. Here sample of code for TOKEN str generation

from binascii import unhexlify 
from binascii import hexlify
from Crypto.Cipher import AES

## Got from WaFoundation framework from function WABuildHash()
wa_build_str = "45e25b6ddecace8d01828dd00bd4ff64".encode() 
## Got data from value which used before call function WABuildHash in WhatsApp 
enc_data = unhexlify(b"6268c9cc61898358c657d1d71932ef2ee7b24109b9668c1962be7d8c1f5ec7f63e9158315f7d6350176d2425894fc6e7") 
key = "landscape".encode() + b"\x00"*7;
data = AES.new(key, AES.MODE_ECB).decrypt(enc_data)
data = data[0:0x28]
token_str = data + wa_build_str
print(token_str.decode())

Output 0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM45e25b6ddecace8d01828dd00bd4ff64

can anyone generate the latest version version 2.22.4.75?

joel-saldana commented 2 years ago

Hi Check here: https://github.com/gradol/yowsup/tree/backup_token/yowsup

image

It Works ur wellcome

joel-saldana commented 2 years ago

Version: 2.22.7.73 ClassesDex: VQUBHJBFbrgBMyHF+XddCg==

abadiops commented 2 years ago

When trying to send a message using yowsup, the following error appears: Centos7 operating system with python updated from version 2.7 to 3.6

Activation already generated config.jason file in root. Some of the colleagues would have a solution?

yowsup.layers.network.layer - Connecting to e14.whatsapp.net:443 yowsup.axolotl.manager - Loaded 812 unsent prekeys yowsup.layers.network.dispatcher.dispatcher_asyncore - Traceback (most recent call last): File "/usr/lib64/python3.6/asyncore.py", line 91, in write obj.handle_write_event() File "/usr/lib64/python3.6/asyncore.py", line 441, in handle_write_event self.handle_connect_event() File "/usr/lib64/python3.6/asyncore.py", line 429, in handle_connect_event self.handle_connect() File "/usr/local/lib/python3.6/site-packages/yowsup/layers/network/dispatcher/dispatcher_asyncore.py", line 34, in handle_connect self.connectionCallbacks.onConnected() File "/usr/local/lib/python3.6/site-packages/yowsup/layers/network/layer.py", line 53, in onConnected self.emitEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECTED)) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 94, in emitEvent emitEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 94, in emitEvent .emitEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 94, in emitEvent er.emitEvent(yowLayerEvent) [Previous line repeated 3 more times] File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 88, in emitEvent if self.upper and not self.upper.onEvent(yowLayerEvent): File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 212, in onEvent stopEvent = stopEvent or s.onEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 109, in onEvent return self.event_callbackseventName File "/usr/local/lib/python3.6/site-packages/yowsup/layers/auth/layer_authentication.py", line 36, in on_connected passive=self.getProp(self.PROP_PASSIVE, False) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 202, in subBroadcastEvent self.broadcastEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 103, in broadcastEvent self.lower.broadcastEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 103, in broadcastEvent self.lower.broadcastEvent(yowLayerEvent) File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 103, in broadcastEvent self.lower.broadcastEvent(yowLayerEvent) [Previous line repeated 1 more time] File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init.py", line 98, in broadcastEvent if self.lower and not self.lower.onEvent(yowLayerEvent): File "/usr/local/lib/python3.6/site-packages/yowsup/layers/init__.py", line 109, in onEvent return self.event_callbackseventName File "/usr/local/lib/python3.6/site-packages/yowsup/layers/noise/layer.py", line 61, in on_auth config = self._profile.config # type: yowsup.config.v1.config.Config AttributeError: 'NoneType' object has no attribute 'config'

yowsup.layers.network.dispatcher.dispatcher_asyncore - handle_close yowsup.layers.network.layer - Disconnected yowsup.layers.axolotl.layer_control - Disconnected, reboot_connect? = False

Whatsapp-Protocol commented 2 years ago

I have solved this problem.

abadiops commented 2 years ago

Friend, whatsapp-Protocol could post the problem resolution link. Even with python 3.6 it still has an error.

SamuelScheit commented 2 years ago

The iOS user agent workaround #3127 will probably stop working eventually, so we need to reverse engineer the structure of the backup token. This is what I've found in a new apk:

// Android copy of Vesta proto. Ground truth here:
//  - https://www.internalfb.com/code/fbsource/xplat/rust/vesta_client/proto/src/messages.proto
package whatsapp;
option java_package = "com.whatsapp.proto";

// Payload stored by successful registration (by `finish_register_request`).
message RegistrationPayload {
  // The secret data to be protected by the HSM system.
  // Holds serialized `WaBackupKeyData` proto.
  optional bytes backup_key_data = 1;
  // OPAQUE protocol third registration message.
  optional bytes r3 = 2;
  // Registration nonce.
  // Deprecated and soon to be removed. Replaced by `transcript` (see protocol spec).
  optional bytes opaque_challenge = 3;
  // History of registration messages: `SHA256(R1, R2, opaque_challenge)`
  optional bytes transcript = 4;
}

// Payload returned on successful account login (by `finish_login_request`).
message LoginPayload {
  // `backup_key_data` from `RegistrationPayload` AES-GCM-128 encrypted with
  // OPAQUE `shared_key`.
  optional bytes backup_key_data_encrypted = 1;
  // Nonce used for AES-GCM-128 encryption of `backup_key_data`.
  optional bytes rk_nonce = 2;
}

// WA-specific proto serialized to/from Vesta `backup_key_data` field.
message WaBackupKeyData {
  // User's backup key AES-GCM-128 encrypted with OPAQUE export key.
  optional bytes aes_k = 1;
  // Nonce used to AES-GCM-128 encrypt `aes_k`.
  optional bytes k_nonce = 2;
}

and

// This file is Android specific
package whatsapp;
option java_package = "com.whatsapp.proto";

message BackupPrefix {
    enum KeyType {
      WA_PROVIDED = 0;
      HSM_CONTROLLED = 1;
    }
    optional KeyType key_type = 1;
    optional WaProvidedKeyData wa_provided_key_data = 2;
    optional HsmControlledKeyData hsm_controlled_key_data = 3;
    optional BackupMetadata backup_metadata = 4;
}

message WaProvidedKeyData {
    optional bytes backup_cipher_header = 1; // 2 bytes. Specifies the version of the file.
    optional string key_version = 2; // 1 byte
    optional bytes server_salt = 3; // 32 bytes
    optional bytes google_id_salt = 4; // 16 bytes
    optional bytes encryption_iv = 5; // 16 bytes

}

message HsmControlledKeyData {
    optional bytes encryption_iv = 1; // 16 bytes
}

message BackupMetadata {
    optional string app_version = 1;
    optional string device_model = 2;
    optional string jid_suffix = 3; // last 2 digits of jid user

    // Number that represents the version of the backup schema. 
    optional int32 backup_version = 4;

    // migration specific fields
    // v1 migrations fields
    optional bool call_log_migration_finished = 5;
    optional bool labeled_jid_migration_finished = 6;
    optional bool message_fts_migration_finished = 7;
    optional bool blank_me_jid_migration_finished = 8;
    optional bool message_link_migration_finished = 9;
    optional bool message_main_migration_finished = 10;
    optional bool message_text_migration_finished = 11;
    optional bool missed_calls_migration_finished = 12;
    optional bool receipt_user_migration_finished = 13;
    optional bool message_media_migration_finished = 14;
    optional bool message_vcard_migration_finished = 15;
    optional bool message_future_migration_finished = 16;
    optional bool message_quoted_migration_finished = 17;
    optional bool message_system_migration_finished = 18;
    optional bool receipt_device_migration_finished = 19;
    optional bool message_mention_migration_finished = 20;
    optional bool message_revoked_migration_finished = 21;
    optional bool broadcast_me_jid_migration_finished = 22;
    optional bool message_frequent_migration_finished = 23;
    optional bool message_location_migration_finished = 24;
    optional bool participant_user_migration_finished = 25;
    optional bool message_thumbnail_migration_finished = 26;
    optional bool message_send_count_migration_finished = 27;
    optional bool migration_jid_store_migration_finished = 28;
    optional bool payment_transaction_migration_finished = 29;
    optional bool migration_chat_store_migration_finished = 30;
    optional bool quoted_order_message_migration_finished = 31;
    optional bool media_migration_fixer_migration_finished = 32;
    optional bool quoted_order_message_v2_migration_finished = 33;
    optional bool message_main_verification_migration_finished = 34;
    optional bool quoted_ui_elements_reply_message_migration_finished = 35;
    optional bool alter_message_ephemeral_to_message_ephemeral_remove_column_migration_finished = 36;
    optional bool alter_message_ephemeral_setting_to_message_ephemeral_setting_remove_column_migration_finished = 37;
    // end of v1 migrations fields
}
SamuelScheit commented 2 years ago

This is what I've found about HSM: https://developers.facebook.com/docs/whatsapp/on-premises/reference/messages#hsm-object but I don't know if it has anything to do with it

Whomakes commented 2 years ago

can anyone make the latest whatsapp token for ios 2.22.9.76?

1612na commented 2 years ago

My advice for Yowsup users is to read the reply comments often, there I found a successful way to overcome BAD PARAM, BACKUP_TOKEN Error,

`C:\wapy>py yowsup-cli registration --requestcode sms --config-phone 62857xxxxxxxx --config-cc 62 --config-mcc 510 --config-mnc 01 E 2022-03-15 02:58:18,171 yowsup.config.manager - Could not find a config for profile=62857xxxxxxxx, paths checked: 62857xxxxxxxx:C:\Users\kampret\AppData\Local\yowsup\yowsup\62857xxxxxxxx\config.yo:C:\Users\kampret\AppData\Local\yowsup\yowsup\62857xxxxxxxx\config.json yowsup-cli v3.2.1 yowsup v3.3.0

Copyright (c) 2012-2019 Tarek Galal http://www.openwhatsapp.org

This software is provided free of charge. Copying and redistribution is encouraged.

If you appreciate this software and you would like to support future development please consider donating: http://openwhatsapp.org/yowsup/donate

W 2022-03-15 02:58:18,263 yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead I 2022-03-15 02:58:20,990 yowsup.common.http.warequest - b'{"flash_type":0,"length":6,"login":"62857xxxxxxxx","method":"sms","notify_after":86400,"retry_after":64,"sms_wait":64,"status":"sent","voice_wait":64}\n' status: b'sent' length: 6 method: b'sms' retry_after: 64 login: b'62857xxxxxxxx' sms_wait: 64 voice_wait: 64

C:\wapy>py yowsup-cli registration --register 509944 --config-phone 62857xxxxxxxx yowsup-cli v3.2.1 yowsup v3.3.0

Copyright (c) 2012-2019 Tarek Galal http://www.openwhatsapp.org

This software is provided free of charge. Copying and redistribution is encouraged.

If you appreciate this software and you would like to support future development please consider donating: http://openwhatsapp.org/yowsup/donate

W 2022-03-15 02:58:44,139 yowsup.common.http.warequest - Passing Config to WARequest is deprecated, pass a YowProfile instead I 2022-03-15 02:58:48,638 yowsup.common.http.warequest - b'{"login":"62857xxxxxxxx","security_code_set":false,"status":"ok","type":"new"}\n' { "version": 1, "cc": "62", "client_static_keypair": "2CmcxWCrNcHAKLg4CAvXHBJuRwnbexqTzMP5Nn2CuVGPWa7MgmhEx2mxxxxxxxxxx==", "expid": "l+NPZEUaTA2rxxxxxxxxxx==", "fdid": "61e71fe1-xxxx-xxxx-xxxx-7e58437xxxxx", "id": "IyH4caFFW7tyQb5VTIpx4ixxxxx=", "login": "62857xxxxxxxx", "mcc": "510", "mnc": "01", "phone": "62857xxxxxxxx", "sim_mcc": "000", "sim_mnc": "000" } status: b'ok' login: b'62857xxxxxxxx' type: b'new'`

Nice thing is you said u resolved it and not how

official-MKV commented 2 years ago

Has Anyone fixed this issue please. I was able to locate where the requests take place in the yowsup\yowsup\common\http\warequest.py I generated 2 backup_tokens : Screenshot (34) The first one using the JS code ` const crypto = require("crypto");

const constant = "A\u0004\u001d@\u0011\u0018V\u0091\u0002\u0090\u0088\u009f\u009eT(3{;ES"; let backup_token_constant = "";

for (let i = 0; i < constant.length; i++) { backup_token_constant += String.fromCharCode(constant.charCodeAt(i) ^ 18); } const last_digits = "11234567890".slice(-4);

const base = backup_token_constant + last_digits; const buffer = Buffer.from(base);

const salt = crypto.randomBytes(4); const iterations = 16; const keylength = 16; // in java is the keylen 128 const key = crypto.pbkdf2Sync(buffer, salt, iterations, keylength, "sha1"); const IV = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-128-ofb', key, IV); const encrypted = cipher.update(crypto.randomBytes(20))

const backup_token = Buffer.concat([Buffer.from([0, 2]), salt, IV, encrypted]) console.log(backup_token.toString("hex"))`

and the other one using the python code above ` import secrets from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import OFB from cryptography.hazmat.primitives.ciphers.base import Cipher

BACKUP_TOKEN_CONSTANT = b"S\x16\x0FR\x03\nD\x83\x10\x82\x9A\x8D\x8CF:!i)WA" BACKUP_TOKEN_HEADER = b'\x00\x02'

def get_backup_token(phone: str): tail = phone[-4:].encode("ascii") base = BACKUP_TOKEN_CONSTANT + tail salt = secrets.token_bytes(4) key = PBKDF2HMAC( algorithm=hashes.SHA1(), length=16, salt=salt, iterations=16 ).derive(base) iv = secrets.token_bytes(16) cipher = Cipher(AES(key), mode=OFB(iv)) encryptor = cipher.encryptor() payload = secrets.token_bytes(20) encrypted = encryptor.update(payload) result = b"".join([BACKUP_TOKEN_HEADER, salt, iv, encrypted]) return result.hex() ` But none of them worked

official-MKV commented 2 years ago

Please someone should fix this issue

rohitmali123 commented 2 years ago

Version: 2.22.21 ClassesDex: vZBCF10FCpZe5K5dQdt7fA==