Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Chrome 106 Shuffled Fingerprint #133

Merged
merged 2 commits into from Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 11 additions & 10 deletions u_common.go
Expand Up @@ -173,16 +173,17 @@ var (
HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil}
HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil}

HelloChrome_Auto = HelloChrome_102
HelloChrome_58 = ClientHelloID{helloChrome, "58", nil}
HelloChrome_62 = ClientHelloID{helloChrome, "62", nil}
HelloChrome_70 = ClientHelloID{helloChrome, "70", nil}
HelloChrome_72 = ClientHelloID{helloChrome, "72", nil}
HelloChrome_83 = ClientHelloID{helloChrome, "83", nil}
HelloChrome_87 = ClientHelloID{helloChrome, "87", nil}
HelloChrome_96 = ClientHelloID{helloChrome, "96", nil}
HelloChrome_100 = ClientHelloID{helloChrome, "100", nil}
HelloChrome_102 = ClientHelloID{helloChrome, "102", nil}
HelloChrome_Auto = HelloChrome_102
HelloChrome_58 = ClientHelloID{helloChrome, "58", nil}
HelloChrome_62 = ClientHelloID{helloChrome, "62", nil}
HelloChrome_70 = ClientHelloID{helloChrome, "70", nil}
HelloChrome_72 = ClientHelloID{helloChrome, "72", nil}
HelloChrome_83 = ClientHelloID{helloChrome, "83", nil}
HelloChrome_87 = ClientHelloID{helloChrome, "87", nil}
HelloChrome_96 = ClientHelloID{helloChrome, "96", nil}
HelloChrome_100 = ClientHelloID{helloChrome, "100", nil}
HelloChrome_102 = ClientHelloID{helloChrome, "102", nil}
HelloChrome_106_Shuffle = ClientHelloID{helloChrome, "106", nil} // beta: shuffler enabled starting from 106

HelloIOS_Auto = HelloIOS_14
HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil} // legacy "111" means 11.1
Expand Down
66 changes: 65 additions & 1 deletion u_parrots.go
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"sort"
"strconv"
)
Expand Down Expand Up @@ -500,6 +501,14 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_106_Shuffle:
chs, err := utlsIdToSpec(HelloChrome_102)
if err != nil {
return chs, err
}

// Chrome 107 started shuffling the order of extensions
return shuffleExtensions(chs)
case HelloFirefox_55, HelloFirefox_56:
return ClientHelloSpec{
TLSVersMax: VersionTLS12,
Expand Down Expand Up @@ -1833,6 +1842,61 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
}
}

func shuffleExtensions(chs ClientHelloSpec) (ClientHelloSpec, error) {
// Shuffle extensions to avoid fingerprinting -- introduced in Chrome 106
// GREASE, padding will remain in place (if present)

// Find indexes of GREASE and padding extensions
var greaseIdx []int
var paddingIdx []int
var otherExtensions []TLSExtension

for i, ext := range chs.Extensions {
switch ext.(type) {
case *UtlsGREASEExtension:
greaseIdx = append(greaseIdx, i)
case *UtlsPaddingExtension:
paddingIdx = append(paddingIdx, i)
default:
otherExtensions = append(otherExtensions, ext)
}
}

// Shuffle other extensions
rand.Shuffle(len(otherExtensions), func(i, j int) {
otherExtensions[i], otherExtensions[j] = otherExtensions[j], otherExtensions[i]
})

// Rebuild extensions slice
otherExtIdx := 0
SHUF_EXTENSIONS:
for i := 0; i < len(chs.Extensions); i++ {
// if current index is in greaseIdx or paddingIdx, add GREASE or padding extension
for _, idx := range greaseIdx {
if i == idx {
chs.Extensions[i] = &UtlsGREASEExtension{}
continue SHUF_EXTENSIONS
}
}
for _, idx := range paddingIdx {
if i == idx {
chs.Extensions[i] = &UtlsPaddingExtension{
GetPaddingLen: BoringPaddingStyle,
}
break SHUF_EXTENSIONS
}
}

// otherwise add other extension
chs.Extensions[i] = otherExtensions[otherExtIdx]
otherExtIdx++
}
if otherExtIdx != len(otherExtensions) {
return ClientHelloSpec{}, errors.New("shuffleExtensions: otherExtIdx != len(otherExtensions)")
}
return chs, nil
}

func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
var spec ClientHelloSpec
uconn.ClientHelloID = id
Expand Down Expand Up @@ -1973,7 +2037,7 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
ecdheParams, err := generateECDHEParameters(uconn.config.rand(), curveID)
if err != nil {
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
"To mimic it, fill the Data(key) field manually.", curveID)
"To mimic it, fill the Data(key) field manually", curveID)
}
ext.KeyShares[i].Data = ecdheParams.PublicKey()
if !preferredCurveIsSet {
Expand Down