diff --git a/go.mod b/go.mod index 26a6803..10e1906 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/duo/matrix-qq go 1.20 require ( - github.com/Mrs4s/MiraiGo v0.0.0-20230312172304-71e86b9b3dc4 + github.com/Mrs4s/MiraiGo v0.0.0-20230405122028-22ff0046638a github.com/antchfx/xmlquery v1.3.15 + github.com/fumiama/go-base16384 v1.7.0 github.com/gabriel-vasile/mimetype v1.4.2 github.com/lib/pq v1.10.7 github.com/mattn/go-sqlite3 v1.14.16 diff --git a/go.sum b/go.sum index c3d4320..416fc81 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/Mrs4s/MiraiGo v0.0.0-20230312172304-71e86b9b3dc4 h1:eqpgTvnexYSBxNtCKWc8OJL3CtGSzvEBOTQ41ViKWqs= -github.com/Mrs4s/MiraiGo v0.0.0-20230312172304-71e86b9b3dc4/go.mod h1:mU3fBFU+7eO0kaGes7YRKtzIDtwIU84nSSwTV7NK2b0= +github.com/Mrs4s/MiraiGo v0.0.0-20230405122028-22ff0046638a h1:1n++/PjDcl4FzByEAnM4hT9CNMDOhr3eBYJ9jC0jTds= +github.com/Mrs4s/MiraiGo v0.0.0-20230405122028-22ff0046638a/go.mod h1:mU3fBFU+7eO0kaGes7YRKtzIDtwIU84nSSwTV7NK2b0= github.com/RomiChan/protobuf v0.1.1-0.20230204044148-2ed269a2e54d h1:/Xuj3fIiMY2ls1TwvPKmaqQrtJsPY+c9s+0lOScVHd8= github.com/RomiChan/protobuf v0.1.1-0.20230204044148-2ed269a2e54d/go.mod h1:2Ie+hdBFQpQFDHfeklgxoFmQRCE7O+KwFpISeXq7OwA= github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA= @@ -16,6 +16,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA= +github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak= github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= @@ -62,6 +64,7 @@ github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= diff --git a/internal/encryption/config.go b/internal/encryption/config.go new file mode 100644 index 0000000..9bba427 --- /dev/null +++ b/internal/encryption/config.go @@ -0,0 +1,3 @@ +package encryption + +var T544Signer = map[string]func(int64, []byte) []byte{} diff --git a/internal/encryption/t544/data.go b/internal/encryption/t544/data.go new file mode 100644 index 0000000..2c0da7b --- /dev/null +++ b/internal/encryption/t544/data.go @@ -0,0 +1,30 @@ +//go:build amd64 + +package t544 + +import ( + "archive/zip" + "bytes" + "io" + "unsafe" + + base14 "github.com/fumiama/go-base16384" +) + +var cryptoData = base14.DecodeFromString( + `戒縰幐一丂一一一娠煳樨刀一乀一圀一吷垌脲妘璖蘀丄跾縀一丆橶縐硍笂儸祠婔瓛伄荰且涵箁澜徴唭嵛庋儉犛埫渀皇淛僎侻昰豪楃愨煬尴豀仵矫栐攂縑千瞷劕瞆繍嵜久劒蕨捅臛佤峺蔗毑襱濄葬呟歍癩覥乆萦厰橤刭翖燈伞榠计賎卯嘭测庆蜖予秶浤熦盭偊光紥礌宒梩伂埧禀嚢曉葊杂箼碒播傸类本煻縢萄宴妡藆調矿筌峸螸翣椶儮扴儳贶擣懪皵孽犠嫛縻萍詌奠蛂竀膜蝆茺耈哣絇爃崵蝝滷楷榏篐棔赦僷舆俨剁椦夤垫睩廜胐弑荜藑斛螥呿臬牴竚聈慑蒔猆珟悑譀弭氐桓历哉孔滁勥始浏崜幕仨仞才簦潈纓竔肕浹戯垁捒崒腖坭撅橅婨搅臛孤槟佖濚襹椄梬菀噭癝冾毥蘢嘅旵曫侃懿棘毱蕵烙椁琼傡祤羶椆攨褆枳劭莟蚳蕚巬嘙矲嘬咯彅祫襥幦膯狝楹繦箻潷稛蛿復纉潬攘掜啲滅篇屫悱欧堶矖幁蔝督丝薢聁薊惣橹砖璧碸禱泭賽翲羞俟槗胅費党痼箝玀腅秨唇興溱虝小汁綡它侖叔芴虭墌嚇螖溈熀秓灻媖搫碸綢贷腎嫵兂囟疾貎跧瑘豄殿爥蓆恆榎芤矟訦憄峙坈圪趕熪亙栣柒珯倍塢衑偦楫峾械纙垺爘垜秝謩蒎捤疩汋豽蛢储嗩嵆潲橙蠧市誣楱嬚微茊睙荻肙漦柩荝讞癓禯墕謰墪摏欚笃螼礑皆沵塪艫狁稪索琴夂憤妱堂觛嚹衦竍觠糐翏舭懒莚萻支楰貖许偵呫爔蓐粀艰糬梃枯俏壶謐刂觡枇庿祛妬催歡繩跽洊澎儰覄瞇劾峮穛奤嫆笪孼氁志耡瀀脦壂粲盋宇妕毃嫉娛旍痹吜衦掺臽罦元罧糴淘户惻謵笾囂觔蜐損斢燖莻笠蕟栫其寅祛某簘宭椦觛臃歭脥訍蕱柫絻凯昷翮畗渘球簑忪蛢劂萾娯崎蜃槭斔作曹湲蓣申茮岃撕燩屑譞盼萎裉紦嶰溃簻惆刻簪刵泴恌巰庸筏匸乢誒唛痍徵茽卼帿荛垮浥荝烷桫琯澿涹豘臐跩獌茾藈烧詺豘緗景拾樚滿訄一跿茄稌刔一一渀一一利绰琚乀一丈一傀一侑獣槙呒螉睮匳繑唁丌丬儧脦跛蕇偀掤概蜣裴檮柬欖篠曣葛矊幜晎妌繀胵綔畍偰蟞挚堧賨粚嗩璘匷崍惹幡簱偫泍呸竕尡硱渔豶厾篁擈痘絨茤乯蕞滱簇勃茶絀塐蟖瞅繭唕解誤笉惖肑暙廬罼豚狆咎揊訉妖品沕疗稉狏猊痮觢瑟窇愨椡摓谴祰蒄扫噃盃蜭裣挃崺肖息揁莽焼溒崓荸晩美炏曣聱褎幘珘矐肖滗羶懶帔萉藲璐媹譈哶仜悻衴盈旋穽蠮焛獜粏腨咈猉惼癹竻蘗澃茀氭懺愰灿岷外犅言一跿茄稌刔一一渀一一奚壾脚乀一丈一傀一侕籣槙呒螉睮匴奱攁丈縔冇她赛巭貯恿丞坓玺珏窴萙椓蘈嵌艎悧訇楬砒缎甍菲稻撟摤蘎仛汈奉社忢楉盒曇水碱蜖偧姪繵栤讞恋琗尔沌臔纱懛窃奢筇窴冄榭情憞妡縍磱嬯苜螜惃斓庭繤蕬蝂竨猞腥胒壠纎嵭癞盢抬拱袒笓懚囔幭紒崋詘窄豜爒祽桾礬旬伩觟渺湩穓蒧漞睱亻俸糋华賸帬招狣吼藭圎塘俖佰斯眎緔欇璘撈哷焿涬唖椥暌劧裤蚸担砬氎卼牛禤芗怰條娯啿蒇舆蛂槊睝晽滩譙夌牜一跿茄稌刔一一渀一一塺絏懡偀一亀一僀一俑潢椙揶効灩榓坶氨焱向何盧毿箲贿侁贴劽捝如翕浱杤毴膔謻攴毹菵厽蕴豢矄莕藗瑐苃籷藧斐摗緙藺琒圆奇疃吏儌円祇熁玎籾粆粸说孡羑羙绌婵蟯桚痎喽粦葔歧吽榾涕扖裘橧蓼衒涙虡荟眭矼解窨脸脸堌戌笞蚼簠裏莲薒榘觮杣妌膌膂幅垖摫堫構疜糆琺蟶窩膞椙衟撨旊崾慷擪晁祿宧襼櫗蝾窡眵汳毘覹襟呡譼圫絖蠺章嵻柾瞬崌沌瑎汪祏啜泪嬰氰朜簞尘瑞沬蚼筌葮賒羫粸敳熉埽罾癪覴謳斶夿澭粑肵賫臎姭椬沫濵洈焳焳滨盫覃羙纘繰庴賳縴翗喽瀮唽同蕟禡禎崝浯晳獾槧枅屾澶穷蕴簹疅葴翪蓪壳稝蕬緭乻催贕沩覰俘腤嶩燗讯攦孺唽吞脃夦球敵岒媻崜櫻泓田翗唜賞苧聾試葛惻怍矮皬设抝蛂襹襻恺婻脫裥惫矷焌秳烛籧甍尋弛泌呺膉瓠慁溫脤湋旜請搜蝺裨胵盳廢癫膞姉峫裷控姱琚峬乶娽擋糟柛朌棟脜桋侎泟浩楫寪矷祷狭溏嬯枎唍咂压例澫澣溢艵翇藓捇旞讕婽词婵蔷猹襻熝艪犦苼蕯籸碻灳翽汗蝍篡紌珌文乕僱狎蚣綄掴賟獭罏揼彥嚷熼簹糯洭滌蜺璸蛱菲茦撰諡绑砙当请欯臌珨端戔蓆袘柵政杹烾罓消奟葟柎攼歸紭冊伖燖槫膻眵襴尧澣罀烁脳焳溨苑蟓覫艑矣觓舞毨徑覻堫敾蓊粜苳烾纲愸螾淐森葓薸码焏掋糶豔掇喙见筗詄摰螝趷荧篢禳俘滪昘簙稺爓幷絣奜泺咸裻瓨盫豿佳瓚曧絟噝凟祣厽寫臄爯药碹睜娙甎偻蟖珐诋蓓奟尟続苍憽盭寝咃匃姟浍挝涴氨婜婻萲翗俯枃屘罻搒误曋唜耳汷掹主掝寮矎腽桢许殑呇呧冒瞃仅绝碿穑蟒跆傼撺磎击苴苮受薫專羓僱滈蝱摱櫳奚泷菑菷矬孲譋慛汫澸涏至糷巑粏棹筄矔挗曃襦塸篕纹貘菻翀僓觇跽姷煏卺肔獳脑洿緽垵蘩拡諑盱縲翇嵗眣懧榟棂藧瀸蟫圎毟袮桝浜蕟梾毁厯曅捇僡磡盀琲槒氹廋螰矅螻袚嫸禛絓井篹板慅敜喇疎否薾螰剐孜宫簎痞羧緼徢覸榾抙掯蓛繳碎竧峿桕櫅虨瘘粚咸忲製賓壼膒祹设搝汹撸婤橦樳儑樹樴栽欝橱臩帥跻糆士盫臞羔嵻橅纮葛袥孑臲篷菴婮慹敬倘嫎寪洃玩苹袲簵蜺毬罬磴玴藏泼聅擽琰搐朝檞簏夬溒姌藗棸怘咭簏唗痚纗蟼参屽舃巢况棹嵮豼犊浞萞觥耱苃葠楽徣櫿嗡瞤詶磗紸藕蓣澥牗橮咎傊心儃瞖慎伮讬坳矷择盓濷絫楳氋疷簻詮琗臖藞罢恩蔮毸螕簾儖嘿吞褹攋诧确盱詔撀犴永塘賻烲舨婐岼槲滵扽窖筨熮搌膃乕矣膧薱獏臸榟慅薄觷嶗睴覵唲蕴柡樝拗椛庰籯薿稣潽簥禦煡滌虰想僞荗覛诟吜倆夆奌膌膂盓忧懮桡大粴朚觚芷簏唾莆簽蒍訬狭萚献糮胢攑蒭谼珇甓羵荢蒠蠏泌呢冖篺筌崨畭捜旜豃倏腻坸痓趼嚇愬粔九罹讬硻薲睎嗞训筱褌綇瓮腽誧礕官峄嗣蟽柖贘氮旪懕裺癆慪蟌淯愷虿姦蟮蛢誾伫貇嗹畽趶唽褰滀荵诏媵濯籭煏泺蠚蛫狳竁甬暪檿艑螎紝蕳磮湋赃妺奧菥玽蛖泻肖崴競蚊諬啺机涹徂懗菗痶覢櫎仂元垶敊倬賺炲褺泷茵志蔹焅漦濕旇芏璷懒费椻歡浾葏蛍愍睷螕碢评詫椵讘咇瑇卯卹偍襳睷豟凁织盁牺湸蚓慡蔢璃嵻塘賻磴穥臞薐蟌筡膞榻薝喸瞋浗婋苏緆斎毼瀩嬮磰珥譧淞堃會泌呦熛紅夃秆磬膕獳赿栠蚅膇竁璮蚹讈圶聑苑菇喽焮泶掩蛳薵笯糯俄覉茵讌粵燦殰苿搢糷尵莪夿愠奨岈洱棋溢幾诛愍蝹礖斾号諏志脆柃滢灍羖憅嬆薙媅宜嵻硴話觚肇絻峓田羷蝼肩費菍畛籆刿哬紥疺疎楡婧毰秆瓽憛硘誩嶝簏兆燇之嗟欸蟞叹煖疦覿曃斞專抟汰蘨猜窪粏嫝涭焍泷猕荴衏巶榷肾沚詪蘒笷榑漏羓埣矅蜽脴槫燦僉硋熇兆渝嫝叏猩欵杮咎傈得埋盱牱瑰脌歱翏玩諗埣尝曟喹补狻沥翟煐杺撾媴賕譯瞖籷羒反珼擱斝滯儃姏崙視瓕綇環覍纹赖詗劂奌窰枌瓖攽罹枖岸賺蒲蟩褭臞讑溙签厼憫哽胙褉嫩能柗栝姥姫豓留孰瘘稙篟癣孶蠵痥豉慆燇下兖燏介啜嬚崜儬橳譴捱请宵濏綧瘻嵥槳缓孟尔見粺箶蚊燕秵旘孩綟甩愌婎赑箷汗蝂肬柱幹絿籣棹柔蕻娽琇冂灑胊狡桥犑硣觮楫兜絻咖诏管秎斝败奒瀛蝉攻岓臟囖哱挎篮橁蠱枫赦蝸綼磣罠乢艹蚉胴艵诧硪賾矗璝懖哈栤听啞讬硻滱觙勃觏儑楟櫱屚艶赴藫员慳裙裢腷厔嶣蝴豻綦奻畷甡炗偅仅蛓翕绠皔檲盹倭畻谶趴蕱惥臑滍觘胗姝憥儶啲塨嫻袊胬襾淠攀丿践伬億匀一丠一一丄嶝簠傀帀一伀丂縀丁艡暛呕讈籢桛渀万跾曟啷緉祯罌世檯賗磝窨夥诺摑贊蕒炯甩唬僟讓垍燿洰芥蝼攝滄挄翈許灘厚俄瘎妬疲歂昲繨楮撨匣絚脩蛋虅嵄仭嘿夕箫妾屒狅焿廯碾舴苎卅豀痵仲涨扨興豊欸譯奭的廿諴竐繏穟珑佼悝谽朗得宂住蔈炩倡哮簅寥蘯槠媎溤爘牜纴裆塆揤汹誃殶寕憪擅槓硥沫溋矠献唩祌榣歴嗒觘簩績筙犀巘屡孕覘椄殞虾垁厧枎猦翨涧展堷蛊吤宿螐璄呤笏稕妱昄一跿茄稌刔一一渀一一尊终簊侀一丘一僀一俑潢椙揶媹灩榀一槿蜀一一一倃偂绐蘐吒历激昔椝叄満纐稴専滲芜蜶儂煣皸爎偏脒媨帘怖咇么楁拙旡幹桎檛佡荍卿暆但翑橈咅著譅吜功琤材民毚抵皀纐稴専囎枻蕻灃栊瓊贉煘粷嗲堏奉膓昪巯松畘稺瞢緬庸螯湼誣亣曨簤儢絇熵疍僬秺炌宋樿撾倸圿婈肠蠧譳蘚曰烮芥祃蚇痙瓮爆仭覻蓐琳埂蓕弙炖蒇商杈呪脥噬嗕蛾嬩紖攠糔羨孁獿苦爑墘詔喇媏憫択薢煺獔涘慜瓝摽栏穋獡艗凹蜵矝氄袧揇圔柽燗甔繋纁昔墼箬襢拨稆曕牖籷攒殙掰莟傖潲巧旀蒥谛穒兛厩藅匟榖杏眠彰怸蜰嬭聋袦令揑峱潆捷朷蚎化斄愞贷櫞牼裐衽洐筚犵絾幷堢來什殽瓚萋兿赘堸愙狠毬晬掷祺緢嫅奩枕炳莽卒榌肐嫄尦峉恱苨汃显禁毙奬薥倴蝍蚲蘟繥篒擌惏琵侨囇玚菄蚓膮櫒倥傿瑻弁痉絺凃瑆絓栯嶽宰廩嵯彂畑瞽淕粩涨贰璨珖磿胘晇粳裐洤蒚觧杷疙褎炸法嵬粺橗昳笻秀焼澶襭帼嚾蛤炌簐擫疃屻亻膊昤賆槮呄緶台堄萷摶纨艈業蛄瞗螼羫咥掤娖愢穩癸独碽溪觐嫊矮藸抳碗壳荜舮九擸哒糃寫娣抾台衁祚謞耪彍烐濹炏箫檣肇娷夣嶾帢薬憮恴章爷懐桛炓茍溹熒擏壇嚮桗吠剡岉臤弲禺矿乨趠褦粰檢胮瑸滂擳纈獙擮槊妜榘貏怺啳款絨萹虹謾噋匥棞財覄坟廼溨菴儋貁碕勜繮槬诶爑瑣珼菓翹藻激敇柯涫孓勥認綹蜑猰欎寜斑蒳浆扖惓羾撰簎犯窌庘傶犿巃虛棦瘭兡移墔焃燠嘸昤侌灢嚰樞垒獧佐搪榞牆膺篱唊癎梇挰喯巫擥剂謽禙莡蓌膧搚臩狆牑昌蝳沅塽圡慚圍萩烊褳幽烑塬凑徿洯等溗焴箶姀畜媎贐嫕粒哰朸擹聻爈獌證榠窹俻擾譸羆桙谷癶聑淽罦疸杷賌牝皅巟膠捨猟懪祘礕贞哙嶾捼粋茊繋蛧譀疩埠玷繎弿玍纄赤薚勉喾刾賯蘽芐泋姌络忺梞蚟居袨屒礁觋忏夗矧噎寯啇贵挪磙痜蝰澦栜詶婂卂橱咡簡婷繜幩譹菂氃朥侯意朶度畀呯茁哽扵胃厛歡忧尘曷肴熴聡蔈爾仱痙屗絲螗栰捾瀉筮栁篻垕灌墺蚧菘湞篰畗瘑肃貓揯烘嵒彔築盭硝徬峦檉捊猰猱皴嵉柟產戍筋悒燑樄贖亍徲扌瀺兏讝沺怅嫿涹碨欧牣詮噔禵盼箮蒰磅甌籚主瞨傿楆塷艂譮剫唁裍甮畔腋厐疖斎祶勲奉堭搣搁刦磜舮爽誩樒谠埊絵房罖債葙謆哪寽瓅峑堗羿尶悩薗慌潘睞痝溱擛峨斠统朸砜帓畼讳椅炽苺衧哉欳氕搸凴慈罴茁菌杴予懕媧犲詷夣衈瑄洤滠塚抜誗褴涖諒槈赳捰胼船广繋婀捵翇塷羄瞏匪莄艶藬失肷孿爠蛁艶淰芏櫆胿廢祟姅諁罞榣緱伇峞文蔁俼崯巔倎賿跞積螒笩貑係枹硻罖簒粻襅琨貎菣嗗槨偿漜挭曙喜杏砦瘾扩咣珣帐七跿戒縰幐一丂一一一勗脫噘一丄一一夀一商厉穥旙僦垥籢昹氦涇牣螸呖妝潤蛁湀七跿戒縰幐一丂一一一幗堷幜一丄一一夀一商厉穥旙惦垥糲屝喜貨敁哏蓟礩糥趚纲一仿跔劰娐戀一亀一一丿罨貜簀一净一下一万待灬杗葢螉睮估儑刀帀丰屰缚襅催縩瘠澇傂皞婄庑爔欃僁忑穼唃叅谀一巿譁夁亅丁帀一倀一一丰溍腰瘐一丁一两一一一一一一一一一丘蔦嫌耮暚擥伬伂匀佀一丈一一丁傜崉澠刀一亀一瘀一一一一一一七刐一朙搶讑献暚擥伬伂匀佀一丈一一丂莢緬羠刀一亀一瘀一一一一一一万娔一杛琶讑献暚擥伬伂匀佀一丈一一丂疫苴谐爀一嘀一稀一一一一一一下战一欘搦羕浡妘璖蝁夁亅丁帀一倀一一乃蟛瀀瘄一一帀丬一一一一一一一僼帀丝吖垱獟暋琦玹幋乀潀乐一丂一一一蘫儢蘨吀一习一夀一一一一一一七耑一商厉穥旘胦垥籐惀帡帀戀一亀一一丄菳壈搀一伀一下一一一一一一一严吀万待灬杗葂螉睮戒縐噐且一一渀一一刕肍舗一丁一一僀一一一一一一一朆一俑潢椙揶抹灩榔劰刈戀匀一丠一一丏詚嶧妀一仰一丂縀一一一一一一丩侀丁艡暛呕讘籢桛猄稔吀一一爀圀赀帀凬昀一一㴃`, +) + +var cryptoZip, _ = zip.NewReader(bytes.NewReader(cryptoData), int64(len(cryptoData))) + +func readData[T any](name string) T { + f, err := cryptoZip.Open(name) + if err != nil { + panic(err) + } + data, err := io.ReadAll(f) + if err != nil { + panic(err) + } + return *(*T)(*(*unsafe.Pointer)(unsafe.Pointer(&data))) +} diff --git a/internal/encryption/t544/encryption.go b/internal/encryption/t544/encryption.go new file mode 100644 index 0000000..a2c6bad --- /dev/null +++ b/internal/encryption/t544/encryption.go @@ -0,0 +1,65 @@ +//go:build amd64 + +package t544 + +import ( + "encoding/binary" + "hash/crc32" + "io" +) + +var crc32Table = func() (tab crc32.Table) { + f, err := cryptoZip.Open("crc32.bin") + if err != nil { + panic(err) + } + data, err := io.ReadAll(f) + if err != nil { + panic(err) + } + for i := range tab { + tab[i] = binary.LittleEndian.Uint32(data[i*4 : (i+1)*4]) + } + return +}() + +//go:noescape +func tencentCrc32(tab *crc32.Table, b []byte) uint32 + +//go:noescape +func sub_a([]byte, []uint32) + +//go:noescape +func sub_b([]byte, []uint32) + +//go:noescape +func sub_c(*[16][16]byte, []byte) + +//go:noescape +func sub_d(*[16]byte, []byte) + +//go:noescape +func sub_e(*[256][6]byte, []byte) + +//go:noescape +func sub_f(*[16]byte, *[15]uint32, *[16][16]byte) (w [44]uint32) + +//go:noescape +func sub_aa(int, *[16][2][16][16]byte, *[16]byte, []byte) byte + +// transformInner see com/tencent/mobileqq/dt/model/FEBound +// +//go:noescape +func transformInner(*[0x15]byte, *[32][16]byte) + +//go:noescape +func initState(*state, []byte, []byte, uint64) + +func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) { + c.nr = nr + c.p = 0 + initState(c, key, data, counter) +} + +//go:noescape +func refreshState(c *state) diff --git a/internal/encryption/t544/encryption_amd64.s b/internal/encryption/t544/encryption_amd64.s new file mode 100644 index 0000000..2460145 --- /dev/null +++ b/internal/encryption/t544/encryption_amd64.s @@ -0,0 +1,669 @@ +//go:build amd64 +// +build amd64 + +#include "textflag.h" + +DATA LC0<>+0(SB)/4, $1634760805 +DATA LC0<>+4(SB)/4, $857760878 +DATA LC0<>+8(SB)/4, $2036477234 +DATA LC0<>+12(SB)/4, $1797285236 +GLOBL LC0<>(SB), NOPTR, $16 + +TEXT ·sub_a(SB), NOSPLIT, $0-48 + MOVQ a+0(FP), DI + MOVQ b+24(FP), CX + MOVQ CX, DX + MOVBLZX 3(CX), CX + XORB CX, (DI) + MOVBLZX 2(DX), CX + XORB CX, 1(DI) + MOVBLZX 1(DX), CX + XORB CX, 2(DI) + MOVBLZX (DX), CX + XORB CX, 3(DI) + MOVBLZX 7(DX), CX + XORB CX, 4(DI) + MOVBLZX 6(DX), CX + XORB CX, 5(DI) + MOVBLZX 5(DX), CX + XORB CX, 6(DI) + MOVBLZX 4(DX), CX + XORB CX, 7(DI) + MOVBLZX 11(DX),CX + XORB CX, 8(DI) + MOVBLZX 10(DX),CX + XORB CX, 9(DI) + MOVBLZX 9(DX), CX + XORB CX,10(DI) + MOVBLZX 8(DX), CX + XORB CX,11(DI) + MOVBLZX 15(DX),CX + XORB CX,12(DI) + MOVBLZX 14(DX),CX + XORB CX,13(DI) + MOVBLZX 13(DX),CX + XORB CX,14(DI) + MOVBLZX 12(DX),DX + XORB DL,15(DI) + RET + +TEXT ·sub_b(SB), NOSPLIT, $0-48 + MOVQ a+0(FP), DI + MOVQ b+24(FP), CX + MOVQ CX, DX + MOVBLZX 3(CX), CX + XORB CX, (DI) + MOVBLZX 6(DX), CX + XORB CX, 1(DI) + MOVBLZX 9(DX), CX + XORB CX, 2(DI) + MOVBLZX 12(DX),CX + XORB CX, 3(DI) + MOVBLZX 7(DX), CX + XORB CX, 4(DI) + MOVBLZX 10(DX),CX + XORB CX, 5(DI) + MOVBLZX 13(DX),CX + XORB CX, 6(DI) + MOVBLZX (DX), CX + XORB CX,7(DI) + MOVBLZX 11(DX),CX + XORB CX,8(DI) + MOVBLZX 14(DX),CX + XORB CX,9(DI) + MOVBLZX 1(DX), CX + XORB CX,10(DI) + MOVBLZX 4(DX), CX + XORB CX,11(DI) + MOVBLZX 15(DX),CX + XORB CX,12(DI) + MOVBLZX 2(DX), CX + XORB CX,13(DI) + MOVBLZX 5(DX), CX + XORB CX,14(DI) + MOVBLZX 8(DX), DX + XORB DL,15(DI) + RET + + +TEXT ·sub_c(SB), NOSPLIT, $0-32 + MOVQ a+0(FP), DI + MOVQ b+8(FP), SI + MOVQ SI, AX + MOVBLZX (SI), SI + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 1(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, (AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 2(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 1(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 3(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 2(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 4(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 3(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 5(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 4(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 6(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 5(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 7(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 6(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 8(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 7(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 9(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 8(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 10(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 9(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 11(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 10(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 12(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 11(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 13(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 12(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 14(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 13(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVBLZX 15(AX), SI + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 14(AX) + MOVL SI, CX + ANDL $15, SI + SHRL $4, CX + SHLL $4, CX + ADDL SI, CX + MOVLQSX CX, CX + MOVBLZX (DI)(CX*1), CX + MOVB CX, 15(AX) + RET + +TEXT ·sub_d(SB), NOSPLIT, $24-32 + MOVQ t+0(FP), BX + MOVQ s+8(FP), DI + MOVOU (DI), X0 + MOVOU X0, in-16(SP) + MOVQ $16, CX + ADDQ $15, DI + PUSHFQ + STD +lop: + LEAQ -1(CX), AX + XLAT + LEAQ in-16(SP)(AX*1), SI + MOVSB + LOOP lop + POPFQ + RET + +TEXT ·sub_e(SB), NOSPLIT, $0-32 + MOVQ a+0(FP), DI + MOVQ n+8(FP), SI + MOVQ $4, AX +lop: + MOVBQZX -4(SI)(AX*4), DX + MOVBQZX -3(SI)(AX*4), CX + MOVBQZX -2(SI)(AX*4), R10 + MOVBQZX -1(SI)(AX*4), R8 + LEAQ (DX)(DX*2), R9 + LEAQ (R9*2), R9 + LEAQ (CX)(CX*2), R11 + LEAQ (R11*2), R11 + LEAQ (R10)(R10*2), BX + LEAQ (BX*2), BX + MOVB DX, R13 + XORB CX, DX + XORB R10, CX + MOVB (DI)(R9*1), R12 + XORB 1(DI)(R11*1), R12 + XORB R8, R10 + XORB R12, R10 + MOVB R10, -4(SI)(AX*4) + MOVB (DI)(R11*1), R10 + XORB 1(DI)(BX*1), R10 + XORB R8, R13 + XORB R10, R13 + MOVB R13, -3(SI)(AX*4) + MOVB (DI)(BX*1), R10 + LEAQ (R8)(R8*2), R8 + LEAQ (R8*2), R8 + XORB 1(DI)(R8*1), R10 + XORB R10, DX + MOVB DX, -2(SI)(AX*4) + MOVB 1(DI)(R9*1), DX + XORB (DI)(R8*1), DX + XORB DX, CX + MOVB CX, -1(SI)(AX*4) + DECB AX + JNZ lop + RET + +TEXT sub_ab<>(SB), NOSPLIT, $0-24 + MOVQ s+0(FP), DI + MOVQ w+8(FP), SI + MOVL SI, AX + MOVL SI, CX + MOVL SI, DX + SHRL $28, AX + SHRL $24, CX + ANDL $15, CX + SALL $4, AX + ADDL CX, AX + MOVBLZX SI, CX + MOVBLZX (DI)(AX*1), AX + MOVBLZX (DI)(CX*1), CX + SALL $24, AX + ORL CX, AX + MOVL SI, CX + SHRL $8, SI + SHRL $8, CX + ANDL $15, SI + ANDL $240, CX + ADDL SI, CX + MOVBLZX (DI)(CX*1), CX + SALL $8, CX + ORL CX, AX + MOVL DX, CX + SHRL $16, DX + SHRL $16, CX + ANDL $15, DX + ANDL $240, CX + ADDL CX, DX + MOVBLZX (DI)(DX*1), DX + SALL $16, DX + ORL DX, AX + MOVQ AX, retval+16(FP) + RET + +TEXT ·sub_f(SB), NOSPLIT, $24-68 + MOVQ k+0(FP), DI + MOVQ r+8(FP), SI + MOVQ s+16(FP), DX + MOVQ $w+24(FP), CX + MOVQ CX, R10 + MOVQ SI, R9 + MOVQ DX, R8 + MOVL $4, BX + MOVL (DI), AX + BSWAPL AX + MOVL AX, (CX) + MOVL 4(DI), AX + BSWAPL AX + MOVL AX, 4(CX) + MOVL 8(DI), AX + BSWAPL AX + MOVL AX, 8(CX) + MOVL 12(DI), AX + BSWAPL AX + MOVL AX, 12(CX) + JMP inner +for: + XORL -16(R10)(BX*4), AX + MOVL AX, (R10)(BX*4) + ADDQ $1, BX + CMPQ BX, $44 + JE end +inner: + MOVL -4(R10)(BX*4), AX + TESTB $3, BX + JNE for + ROLL $8, AX + MOVQ R8, 0(SP) + MOVL AX, 8(SP) + CALL sub_ab<>(SB) + MOVQ 16(SP), AX + LEAL -1(BX), DX + SARL $2, DX + MOVLQSX DX, DX + XORL (R9)(DX*4), AX + JMP for +end: + RET + +TEXT ·sub_aa(SB), NOSPLIT, $0-56 + MOVQ i+0(FP), DI + MOVQ t+8(FP), SI + MOVQ b+16(FP), DX + MOVQ m+24(FP), CX + MOVL DI, AX + MOVLQSX DI, DI + MOVQ SI, R8 + MOVQ DX, SI + MOVBLZX (CX)(DI*1), CX + ANDL $15, AX + MOVBLZX (SI)(AX*1), SI + MOVQ AX, DX + MOVL CX, AX + SALQ $9, DX + ANDL $15, CX + SHRB $4, AX + MOVL SI, DI + ADDQ R8, DX + SALQ $4, CX + ANDL $15, AX + SHRB $4, DI + ANDL $15, SI + SALQ $4, AX + ANDL $15, DI + ADDQ DX, AX + ADDQ CX, DX + MOVBLZX (AX)(DI*1), AX + SALL $4, AX + ORB 256(SI)(DX*1), AX + MOVQ AX, retval+48(FP) + RET + +// func transformInner(x *[0x15]byte, tab *[32][16]byte) +TEXT ·transformInner(SB), NOSPLIT, $0-16 + MOVQ x+0(FP), DI + MOVQ tab+8(FP), SI + MOVQ DI, AX + MOVL $1, CX + MOVQ SI, DI + MOVQ AX, SI +lop: + MOVBLZX (SI), R8 + LEAL -1(CX), AX + ADDQ $1, SI + ANDL $31, AX + MOVL R8, DX + SALL $4, AX + ANDL $15, R8 + SHRB $4, DX + MOVBLZX DX, DX + ADDL DX, AX + CDQE + MOVBLSX (DI)(AX*1), AX + SALL $4, AX + MOVL AX, DX + MOVL CX, AX + ADDL $2, CX + ANDL $31, AX + SALL $4, AX + ADDL R8, AX + CDQE + ORB (DI)(AX*1), DX + MOVB DX, -1(SI) + CMPL CX, $43 + JNE lop + RET + +TEXT ·initState(SB), NOSPLIT, $0-64 + MOVQ c+0(FP), DI + MOVQ key+8(FP), SI + MOVQ data+32(FP), R8 + MOVQ counter+56(FP), AX + MOVOA LC0<>(SB), X0 + MOVUPS X0, (DI) + MOVOU (SI), X1 + MOVOU (DI), X3 + MOVUPS X1, 16(DI) + MOVOU 16(SI), X2 + MOVQ AX, 48(DI) + MOVUPS X2, 32(DI) + MOVQ (R8), AX + MOVUPS X3, 64(DI) + MOVQ AX, 56(DI) + MOVQ 48(DI), AX + MOVUPS X1, 80(DI) + MOVUPS X2, 96(DI) + MOVUPS X6,112(DI) + RET + +TEXT sub_ad<>(SB), NOSPLIT, $8-8 + MOVQ a+0(FP), DI + MOVQ DI, AX + MOVL 40(DI), R10 + MOVL 12(DI), R12 + MOVL 44(DI), BP + MOVL 16(DI), DX + MOVL (DI), R15 + MOVL 48(DI), R9 + MOVL 20(DI), SI + MOVL 32(DI), R11 + ADDL DX, R15 + MOVL 4(DI), R14 + MOVL 52(DI), R8 + XORL R15, R9 + MOVL 24(DI), CX + MOVL 8(DI), R13 + ROLL $16, R9 + ADDL SI, R14 + MOVL 36(DI), BX + MOVL 56(DI), DI + ADDL R9, R11 + XORL R14, R8 + ADDL CX, R13 + XORL R11, DX + ROLL $16, R8 + XORL R13, DI + ROLL $12, DX + ADDL R8, BX + ROLL $16, DI + ADDL DX, R15 + XORL BX, SI + ADDL DI, R10 + XORL R15, R9 + ROLL $12, SI + XORL R10, CX + ROLL $8, R9 + ADDL SI, R14 + ROLL $12, CX + ADDL R9, R11 + XORL R14, R8 + ADDL CX, R13 + XORL R11, DX + ROLL $8, R8 + XORL R13, DI + ROLL $7, DX + LEAL (BX)(R8*1), BX + ROLL $8, DI + MOVL DX, tmp0-8(SP) + MOVL 28(AX), DX + XORL BX, SI + MOVL BX, tmp1-4(SP) + MOVL R10, BX + MOVL 60(AX), R10 + ROLL $7, SI + ADDL DI, BX + ADDL DX, R12 + ADDL SI, R15 + XORL R12, R10 + XORL BX, CX + ROLL $16, R10 + ROLL $7, CX + ADDL R10, BP + ADDL CX, R14 + XORL BP, DX + XORL R14, R9 + ROLL $12, DX + ROLL $16, R9 + ADDL DX, R12 + XORL R12, R10 + ROLL $8, R10 + ADDL R10, BP + XORL R15, R10 + ROLL $16, R10 + XORL BP, DX + ADDL R9, BP + ADDL R10, BX + ROLL $7, DX + XORL BP, CX + XORL BX, SI + ROLL $12, SI + ADDL SI, R15 + XORL R15, R10 + MOVL R15, (AX) + ROLL $8, R10 + ADDL R10, BX + MOVL R10, 60(AX) + XORL BX, SI + MOVD BX, X1 + ROLL $7, SI + ROLL $12, CX + ADDL DX, R13 + XORL R13, R8 + ADDL CX, R14 + MOVL SI, 20(AX) + ROLL $16, R8 + XORL R14, R9 + MOVL R14, 4(AX) + ADDL R8, R11 + ROLL $8, R9 + XORL R11, DX + ADDL R9, BP + MOVL R9, 48(AX) + ROLL $12, DX + XORL BP, CX + MOVD BP, X2 + ADDL DX, R13 + ROLL $7, CX + PUNPCKLLQ X2, X1 + XORL R13, R8 + MOVL CX, 24(AX) + ROLL $8, R8 + MOVL R13, 8(AX) + ADDL R8, R11 + XORL R11, DX + MOVD R11, X0 + ROLL $7, DX + MOVL DX, 28(AX) + MOVL R8, 52(AX) + MOVL tmp0-8(SP), SI + MOVL tmp1-4(SP), CX + ADDL SI, R12 + XORL R12, DI + ROLL $16, DI + ADDL DI, CX + XORL CX, SI + MOVL SI, DX + ROLL $12, DX + ADDL DX, R12 + XORL R12, DI + MOVL R12, 12(AX) + ROLL $8, DI + ADDL DI, CX + MOVL DI, 56(AX) + MOVD CX, X3 + XORL CX, DX + PUNPCKLLQ X3, X0 + ROLL $7, DX + PUNPCKLQDQ X1, X0 + MOVL DX, 16(AX) + MOVUPS X0, 32(AX) + RET + +TEXT ·refreshState(SB), NOSPLIT, $16-8 + MOVQ i+0(FP), BX + MOVB 128(BX), CX + JE ad + SHRQ $1, CX +fr: + MOVQ BX, 0(SP) + MOVQ CX, c-8(SP) + CALL sub_ad<>(SB) + MOVQ c-8(SP), CX + MOVQ i+0(FP), BX + LOOP fr +ad: + MOVOU (BX), X0 + MOVOU 64(BX), X1 + MOVOU 80(BX), X2 + MOVOU 96(BX), X3 + PADDD X1, X0 + MOVOU 48(BX), X4 + MOVUPS X0, (BX) + MOVOU 16(BX), X0 + PADDD X2, X0 + MOVUPS X0, 16(BX) + MOVOU 32(BX), X0 + PADDD X3, X0 + MOVUPS X0, 32(BX) + MOVOU 112(BX), X0 + PADDD X4, X0 + MOVUPS X0, 48(BX) + RET + +// func tencentCrc32(tab *crc32.Table, b []byte) uint32 +TEXT ·tencentCrc32(SB), NOSPLIT, $0-40 + MOVQ tab+0(FP), DI + MOVQ bptr+8(FP), SI + MOVQ bngas+16(FP), DX + TESTQ DX, DX + JE quickend + ADDQ SI, DX + MOVL $-1, AX +lop: + MOVBLZX (SI), CX + ADDQ $1, SI + XORL AX, CX + SHRL $8, AX + MOVBLZX CX, CX + XORL (DI)(CX*4), AX + CMPQ SI, DX + JNE lop + NOTL AX + MOVQ AX, bngas+32(FP) + RET +quickend: + XORL AX, AX + RET + diff --git a/internal/encryption/t544/encryption_generic.go b/internal/encryption/t544/encryption_generic.go new file mode 100644 index 0000000..cd3b4f0 --- /dev/null +++ b/internal/encryption/t544/encryption_generic.go @@ -0,0 +1,112 @@ +//go:build amd64 + +package t544 + +import ( + "encoding/binary" + "io" +) + +type encryptionData struct { + tableA [16][2][16][16]byte + tableB [16][16]byte + tableC [256][6]byte + tableD [16]byte + tableE [16]byte + tableF [15]uint32 +} + +type state struct { + state [16]uint32 // 16 + orgstate [16]uint32 // 16 + nr uint8 + p uint8 +} + +var crypto = encryptionData{ + tableA: readData[[16][2][16][16]byte]("table_a.bin"), + tableB: readData[[16][16]byte]("table_b.bin"), + tableC: readData[[256][6]byte]("table_c.bin"), + tableD: readData[[16]byte]("table_d.bin"), + tableE: readData[[16]byte]("table_e.bin"), + tableF: func() (tab [15]uint32) { + f, err := cryptoZip.Open("table_f.bin") + if err != nil { + panic(err) + } + data, err := io.ReadAll(f) + if err != nil { + panic(err) + } + for i := range tab { + tab[i] = binary.LittleEndian.Uint32(data[i*4 : (i+1)*4]) + } + return + }(), +} + +func (e *encryptionData) tencentEncryptB(p1 []byte, p2 []uint32) { + const c = 10 + for r := 0; r < 9; r++ { + sub_d(&e.tableD, p1) + sub_b(p1, p2[r*4:(r+1)*4]) + sub_c(&e.tableB, p1) + sub_e(&e.tableC, p1) + } + sub_d(&e.tableD, p1) + sub_b(p1, p2[(c-1)*4:c*4]) + sub_c(&e.tableB, p1) + sub_a(p1, p2[c*4:(c+1)*4]) +} + +func (e *encryptionData) tencentEncryptionB(c []byte, m []byte) (out [0x15]byte) { + var buf [16]byte + w := sub_f(&e.tableE, &e.tableF, &e.tableB) + + for i := range out { + if (i & 0xf) == 0 { + copy(buf[:], c) + e.tencentEncryptB(buf[:], w[:]) + for j := 15; j >= 0; j-- { + c[j]++ + if c[j] != 0 { + break + } + } + } + out[i] = sub_aa(i, &e.tableA, &buf, m) + } + + return +} + +func tencentEncryptionA(input, key, data []byte) { + var s state + s.init(key, data, 0, 20) + s.encrypt(input) +} + +func (c *state) encrypt(data []byte) { + bp := 0 + dataLen := uint32(len(data)) + for dataLen > 0 { + if c.p == 0 { + refreshState(c) + } + var sb [16 * 4]byte + for i, v := range c.state { + binary.LittleEndian.PutUint32(sb[i*4:(i+1)*4], v) + } + for c.p != 64 && dataLen != 0 { + data[bp] ^= sb[c.p] + c.p++ + bp++ + dataLen-- + } + if c.p >= 64 { + c.p = 0 + c.orgstate[12]++ + c.state = c.orgstate + } + } +} diff --git a/internal/encryption/t544/t544.go b/internal/encryption/t544/t544.go new file mode 100644 index 0000000..27e19bc --- /dev/null +++ b/internal/encryption/t544/t544.go @@ -0,0 +1,91 @@ +//go:build amd64 + +package t544 + +import ( + "crypto/md5" + "crypto/rc4" + "encoding/binary" + "math/rand" + + "github.com/duo/matrix-qq/internal/encryption" +) + +const ( + keyTable = "$%&()+,-456789:?ABCDEEFGHIJabcdefghijkopqrstuvwxyz" + table2 = "!#$%&)+.0123456789:=>?@ABCDEFGKMNabcdefghijkopqrst" +) + +var ( + magic = uint64(0x6EEDCF0DC4675540) + key1 = [8]byte{'a', '$', '(', 'e', 'T', '7', '*', '@'} + key2 = [8]byte{'&', 'O', '9', '!', '>', '6', 'X', ')'} +) + +func init() { + encryption.T544Signer["8.9.35.10440"] = sign + encryption.T544Signer["8.9.38.10545"] = sign +} + +// sign t544 algorithm +// special thanks to the anonymous contributor who provided the algorithm +func sign(curr int64, input []byte) []byte { + var crcData [0x15]byte + curr %= 1000000 + binary.BigEndian.PutUint32(crcData[:4], uint32(curr)) + input = append(input, crcData[:4]...) + var kt [4 + 32 + 4]byte + r := rand.New(rand.NewSource(curr)) + for i := 0; i < 2; i++ { + kt[i] = keyTable[r.Int()%0x32] + 50 + } + kt[2] = kt[1] + 20 + kt[3] = kt[2] + 20 + key3 := kt[4 : 4+10] + k3calc := key3[2:10] + copy(k3calc, key1[:4]) + for i := 0; i < 4; i++ { + k3calc[4+i] = key2[i] ^ kt[i] + } + key3[0], key3[1] = k3calc[6], k3calc[7] + key3 = key3[:8] + k3calc[6], k3calc[7] = 0, 0 + rc4Cipher, _ := rc4.NewCipher(key3) + rc4Cipher.XORKeyStream(key3, key3) + binary.LittleEndian.PutUint64(crcData[4:4+8], magic) + tencentEncryptionA(input, kt[4:4+32], crcData[4:4+8]) + result := md5.Sum(input) + crcData[2] = 1 + crcData[4] = 1 + copy(crcData[5:9], kt[:4]) + binary.BigEndian.PutUint32(crcData[9:13], uint32(curr)) + copy(crcData[13:], result[:8]) + calcCrc := tencentCrc32(&crc32Table, crcData[2:]) + binary.LittleEndian.PutUint32(kt[4+32:4+32+4], calcCrc) + crcData[0] = kt[4+32] + crcData[1] = kt[4+32+3] + nonce := uint32(r.Int() ^ r.Int() ^ r.Int()) + on := kt[:16] + binary.BigEndian.PutUint32(on[:4], nonce) + copy(on[4:8], on[:4]) + copy(on[8:16], on[:8]) + ts.transformEncode(&crcData) + encryptedData := crypto.tencentEncryptionB(on, crcData[:]) + ts.transformDecode(&encryptedData) + output := kt[:39] + output[0] = 0x0C + output[1] = 0x05 + binary.BigEndian.PutUint32(output[2:6], nonce) + copy(output[6:27], encryptedData[:]) + binary.LittleEndian.PutUint32(output[27:31], 0) + output[31] = table2[r.Int()%0x32] + output[32] = table2[r.Int()%0x32] + addition := r.Int() % 9 + for addition&1 == 0 { + addition = r.Int() % 9 + } + output[33] = output[31] + byte(addition) + output[34] = output[32] + byte(9-addition) + 1 + binary.LittleEndian.PutUint32(output[35:39], 0) + return output +} diff --git a/internal/encryption/t544/t544_stub.go b/internal/encryption/t544/t544_stub.go new file mode 100644 index 0000000..361f7b4 --- /dev/null +++ b/internal/encryption/t544/t544_stub.go @@ -0,0 +1,7 @@ +//go:build !amd64 + +package t544 + +func init() { + +} diff --git a/internal/encryption/t544/t544_test.go b/internal/encryption/t544/t544_test.go new file mode 100644 index 0000000..1f0f184 --- /dev/null +++ b/internal/encryption/t544/t544_test.go @@ -0,0 +1,22 @@ +package t544 + +import ( + "crypto/rand" + "encoding/hex" + "testing" +) + +func TestT544(t *testing.T) { + r := hex.EncodeToString(sign(0, []byte{})) + if r != "0c05d28b405bce1595c70ffa694ff163d4b600f229482e07de32c8000000003525382c00000000" { + t.Fatal(r) + } +} + +func TestCrash(t *testing.T) { + brand := make([]byte, 4096) + for i := 1; i <= 1024; i++ { + rand.Reader.Read(brand) + sign(123, brand) + } +} diff --git a/internal/encryption/t544/transform.go b/internal/encryption/t544/transform.go new file mode 100644 index 0000000..f8bf1b0 --- /dev/null +++ b/internal/encryption/t544/transform.go @@ -0,0 +1,21 @@ +//go:build amd64 + +package t544 + +type transformer struct { + encode [32][16]byte + decode [32][16]byte +} + +func (ts *transformer) transformEncode(bArr *[0x15]byte) { + transformInner(bArr, &ts.encode) +} + +func (ts *transformer) transformDecode(bArr *[0x15]byte) { + transformInner(bArr, &ts.decode) +} + +var ts = transformer{ + encode: readData[[32][16]byte]("encode.bin"), + decode: readData[[32][16]byte]("decode.bin"), +} diff --git a/internal/user.go b/internal/user.go index 844eafb..a801d59 100644 --- a/internal/user.go +++ b/internal/user.go @@ -14,6 +14,7 @@ import ( "time" "github.com/duo/matrix-qq/internal/database" + "github.com/duo/matrix-qq/internal/encryption" "github.com/duo/matrix-qq/internal/types" "github.com/tidwall/gjson" @@ -29,6 +30,7 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" + _ "github.com/duo/matrix-qq/internal/encryption/t544" // side effect log "maunium.net/go/maulogger/v2" ) @@ -1041,19 +1043,23 @@ func setClientProtocol(device *client.DeviceInfo, protocol int) { } } -func energy(uin uint64, id string, salt []byte) ([]byte, error) { - // temporary solution +func energy(uin uint64, id string, appVersion string, salt []byte) ([]byte, error) { + if localSigner, ok := encryption.T544Signer[appVersion]; ok { + result := localSigner(time.Now().UnixMicro(), salt) + return result, nil + } + signServer := "https://captcha.go-cqhttp.org/sdk/dandelion/energy" response, err := Request{ Method: http.MethodPost, - URL: "https://captcha.go-cqhttp.org/sdk/dandelion/energy", + URL: signServer, Header: map[string]string{"Content-Type": "application/x-www-form-urlencoded"}, - Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&id=%s&salt=%s", uin, id, hex.EncodeToString(salt)))), + Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&id=%s&salt=%s&version=%s", uin, id, hex.EncodeToString(salt), appVersion))), }.Bytes() if err != nil { return nil, err } sign, err := hex.DecodeString(gjson.GetBytes(response, "result").String()) - if err != nil { + if err != nil || len(sign) == 0 { return nil, err } return sign, nil diff --git a/main.go b/main.go index f89a7e3..84ecea4 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,7 @@ func main() { Name: "matrix-qq", URL: "https://github.com/duo/matrix-qq", Description: "A Matrix-QQ puppeting bridge.", - Version: "0.1.6", + Version: "0.1.7", ProtocolName: "QQ", CryptoPickleKey: "github.com/duo/matrix-qq",