Skip to content

Commit

Permalink
feat: Chrome 106 Shuffled Fingerprint (#133)
Browse files Browse the repository at this point in the history
* feat: Chrome 107 fp with shuffler

- added `HelloChrome_107` (not used by `HelloChrome_Auto`)
- added `shuffleExtensions()` to shuffle the order of extensions in a `ClientHelloSpec`

* fix: rename for chronologically accuracy

- Renamed `HelloChrome_107` to `HelloChrome_106_Shuffle` to match the versioning info from https://groups.google.com/a/chromium.org/g/blink-dev/c/zdmNs2rTyVI/m/MAiQwQkwCAAJ
  • Loading branch information
gaukas committed Nov 15, 2022
1 parent 8e1e65e commit 1b3a9ad
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
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 @@ -507,6 +508,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 @@ -1840,6 +1849,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 @@ -1980,7 +2044,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

0 comments on commit 1b3a9ad

Please sign in to comment.