mirror of
https://github.com/Ap0dexMe0/NF-MSL.git
synced 2026-10-15 04:12:08 +02:00
226 lines
6.8 KiB
Markdown
226 lines
6.8 KiB
Markdown
# Netflix MSL Universal Handshake
|
||
|
||
> A cross-platform MSL (Message Security Layer) authentication toolkit for Netflix.
|
||
> Implements a unified handshake layer that works across Android, iOS, Smart TV, Web, and MGK — all driven from a single entry point with shared credential management.
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
- [Configuration](#configuration)
|
||
- [Devices (WVD Files)](#devices-wvd-files)
|
||
- [Platforms](#platforms)
|
||
- [Android](#android)
|
||
- [iOS](#ios)
|
||
- [TV (email/password)](#tv-emailpassword)
|
||
- [TV OTP (pairing code)](#tv-otp-pairing-code)
|
||
- [Web](#web)
|
||
- [MGK (Model Group Key)](#mgk-model-group-key)
|
||
- [Usage](#usage)
|
||
---
|
||
|
||
Install all dependencies:
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
|
||
## Configuration
|
||
|
||
Edit `config.ini` before running anything:
|
||
|
||
```ini
|
||
[NETFLIX]
|
||
EMAIL = your@email.com
|
||
PASSWORD = yourpassword
|
||
```
|
||
|
||
Credentials are read once at startup and passed internally to every platform function. They are **never** accepted as command-line arguments.
|
||
|
||
---
|
||
|
||
## Devices (WVD Files)
|
||
|
||
Two Widevine Device (`.wvd`) files are included in the `devices/` folder:
|
||
|
||
| File | Security Level | Used by |
|
||
|------|---------------|---------|
|
||
| `l3.wvd` | L3 | Android, iOS |
|
||
| `l1.wvd` | L1 | TV, TV OTP |
|
||
|
||
The correct WVD is selected automatically for each platform. The `--wvd` flag lets you override with a custom device file if needed.
|
||
|
||
---
|
||
|
||
## Platforms
|
||
|
||
### Android
|
||
|
||
Emulates a **Samsung Galaxy Z Flip3 (SM-F711N)** running Android 15.
|
||
|
||
**MSL flow:**
|
||
1. Bootstrap HTTP session → obtain `nfvdid` cookie via `appboot`
|
||
2. Widevine key exchange (MSL handshake) using L3 WVD
|
||
3. `VerifyLoginMslRequest` — submits email + password via MSL
|
||
4. Decrypts the response header to extract `useridtoken`
|
||
|
||
**Output:** `netflix_auth_tokens.json`, `netflix_auth_useridtoken.json`, `netflix_auth_cookies.json`
|
||
|
||
---
|
||
|
||
### iOS
|
||
|
||
Emulates an **iPhone 15 Pro Max** running iOS 18.
|
||
|
||
**MSL flow:**
|
||
1. Bootstrap HTTP session → obtain `nfvdid` via `appboot`
|
||
2. Widevine key exchange using L3 WVD
|
||
3. `MembershipStatus` GraphQL probe (anonymous)
|
||
4. `CLCSScreenUpdate` — submits email + password via MSL to `ios.prod.cloud.netflix.com/graphql`
|
||
5. Decrypts the response header to extract `useridtoken`
|
||
|
||
**Output:** `netflix_auth_cookies.json`
|
||
|
||
---
|
||
|
||
### TV (email/password)
|
||
|
||
Emulates an **NVIDIA SHIELD Android TV (2019)**.
|
||
|
||
**MSL flow:**
|
||
1. Obtain `nfvdid` from the Android TV config endpoint
|
||
2. Bootstrap AUI + pre-login `pathEvaluator`
|
||
3. Widevine key exchange using L1 WVD → `mintCookies`
|
||
4. CLCS session initiation (`clcsLegacyMoneyballInitiateSession`)
|
||
5. Multi-step sign-in flow:
|
||
- Navigate welcome landing → web sign-in → email → password path
|
||
- Submit credentials via `clcsScreenUpdate`
|
||
6. Post-login PBO config + token refresh (`getPartnerToken`, `ping`)
|
||
7. Save cookies including `NetflixId`, `SecureNetflixId`, `gsid`
|
||
|
||
**Output:** `netflix_cookies.json`, `useridtoken.json`, `msl_debug_trace.json`, `password_login_response.json`
|
||
|
||
---
|
||
|
||
### TV OTP (pairing code)
|
||
|
||
Same device profile as **TV**, but authenticates via a **one-time pairing code** instead of email/password.
|
||
|
||
**MSL flow:**
|
||
1–3. Same as TV up through `mintCookies`
|
||
4. CLCS session initiation
|
||
5. Navigate to `webSignIn` mode → extract an **8-digit TV code**
|
||
6. **Display the code and poll** `https://www.netflix.com/tv2` until the user activates it from a browser
|
||
7. Send `continueAction` to complete sign-in
|
||
|
||
> **Interactive:** you must visit `https://www.netflix.com/tv2` in a browser and enter the displayed code to proceed.
|
||
|
||
**Output:** `netflix_cookies.json`, `useridtoken.json`
|
||
|
||
---
|
||
|
||
### Web
|
||
|
||
Emulates **Chrome 146 on Windows 10**.
|
||
|
||
**MSL flow:**
|
||
1. Bootstrap anonymous browser session (`netflix.com` → `netflix.com/login`)
|
||
2. `MembershipStatus` GraphQL probe
|
||
3. Extract `clcsSessionId` and `renditionId` from the login page HTML
|
||
4. `CLCSScreenUpdate` — submit email + password directly to `PASSWORD_LOGIN` screen
|
||
5. Optional `CLCSSendFeedback` if the response contains a feedback payload
|
||
6. Open `/browse` to finalize the authenticated session
|
||
7. `CLCSInterstitialProfileGate` probe
|
||
8. ALE provision via MSL (`aleProvision` handshake)
|
||
|
||
**Output:** `netflix_auth_cookies.json`
|
||
|
||
---
|
||
|
||
### MGK (Model Group Key)
|
||
|
||
Uses the **MGK / AUTHENTICATED_DH** MSL key-exchange scheme, authenticating with a pre-provisioned `KpeKph` key pair rather than a Widevine device.
|
||
|
||
**Requires two sidecar files:**
|
||
|
||
| File | Content |
|
||
|------|---------|
|
||
| `KpeKph` | Base64 AES-128 encryption key + Base64 HMAC-SHA256 key, comma-separated |
|
||
| `ESNID` | Model-group identity string (the MGK sender ESN) |
|
||
|
||
These files are discovered automatically in the working directory, any subdirectory, or via environment variables:
|
||
|
||
```bash
|
||
export MSL_KPEKPH_PATH=/path/to/KpeKph
|
||
export MSL_ESNID_PATH=/path/to/ESNID
|
||
```
|
||
|
||
Or pass `--kpekph` on the command line.
|
||
|
||
**MSL flow:**
|
||
1. Load `KpeKph` → derive wrapping key
|
||
2. Generate a DH keypair; build `AUTHENTICATED_DH` key-request with `mechanism=MGK`
|
||
3. Perform handshake → derive session encryption + HMAC keys from shared secret
|
||
4. Send `EMAIL_PASSWORD` user-auth message → receive `useridtoken`
|
||
|
||
**Output:** `useridtoken_mgk.json`, `netflix_auth_cookies_mgk.json`
|
||
|
||
---
|
||
|
||
## Usage
|
||
|
||
```bash
|
||
# Android
|
||
python main.py --platform android
|
||
|
||
# iOS
|
||
python main.py --platform ios
|
||
|
||
# TV (email/password)
|
||
python main.py --platform tv
|
||
|
||
# TV OTP (pairing code — interactive)
|
||
python main.py --platform tv_otp
|
||
|
||
# Web (Chrome emulation)
|
||
python main.py --platform web
|
||
|
||
# MGK (Model Group Key)
|
||
python main.py --platform mgk
|
||
|
||
# MGK with explicit KpeKph path
|
||
python main.py --platform mgk --kpekph /path/to/KpeKph
|
||
|
||
# Override WVD device for Android/iOS/TV/TV-OTP
|
||
python main.py --platform android --wvd /path/to/device.wvd
|
||
|
||
# Force a fresh MSL key exchange (ignore cached keys)
|
||
python main.py --platform tv --new-msl
|
||
|
||
# Disable TLS verification (not recommended)
|
||
python main.py --platform web --no-verify
|
||
|
||
# Pass a reCAPTCHA token for web login
|
||
python main.py --platform web --recaptcha-token <token>
|
||
```
|
||
|
||
### All flags
|
||
|
||
| Flag | Applies to | Description |
|
||
|------|-----------|-------------|
|
||
| `--platform` / `-p` | all | **Required.** `android`, `ios`, `tv`, `tv_otp`, `web`, `mgk` |
|
||
| `--wvd` | android, ios, tv, tv_otp | Path to `.wvd` Widevine device file (optional override) |
|
||
| `--kpekph` | mgk | Path to `KpeKph` key file |
|
||
| `--new-msl` | all | Force a fresh MSL handshake, ignoring any cached keys |
|
||
| `--no-verify` | all | Disable TLS certificate verification |
|
||
| `--recaptcha-token` | web | reCAPTCHA v2 response token |
|
||
|
||
---
|
||
|
||
MSL key caches are reused across runs to avoid a full handshake every time. They expire automatically when the master token has fewer than 10 hours remaining.
|
||
|
||
---
|
||
|
||
**Big thanks to [Hugoved](https://github.com/Hugoved)**
|
||
- for the foundational work on MSL (Message Security Layer) reverse engineering, and the original pywidevine implementation that made this unified handshake toolkit possible. |