diff --git a/.gitignore b/.gitignore index a94626b..87df5a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,24 @@ - *.pyc - \ No newline at end of file +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c8a7988 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Victor Golovanenko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 17aa6cd..6d7ce66 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,66 @@ -# WPSpin -WPS pin generator Python 3 module. Thanks [3WiFi Wireless Database](https://github.com/binarymaster/3WiFi) for WPS pin algorithms +# WPS PIN generator written in Python 3 +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/wpspin.svg)](https://pypi.python.org/pypi/wpspin/) +[![PyPI version shields.io](https://img.shields.io/pypi/v/wpspin.svg)](https://pypi.python.org/pypi/py3wifi/) +![PyPI - Downloads](https://img.shields.io/pypi/dm/wpspin) +## Overview +WPS PIN generator uses known MAC address based algorithms commonly found in routers firmware to generate their default PINs. The PIN can be used with programs like [Reaver](https://github.com/t6x/reaver-wps-fork-t6x), [Bully](https://github.com/aanarchyy/bully) or [OneShot](https://github.com/drygdryg/OneShot) to recover Wi-Fi password. +## Installation +``` +pip install wpspin +``` +Or you can install from source with: +``` +git clone https://github.com/drygdryg/wpspin.git +cd wpspin/ +python setup.py install +``` +## Usage +### Command line tool +``` +wpspin [-A] MAC +Required arguments: + MAC : target MAC address to generate PIN code. Example: 11:22:33:44:55:66 +Optional arguments: + -A, --get-all : get all PIN codes in addition to the suggested ones for a single MAC +``` +Example: +``` +$ wpspin 54:A0:50:75:D2:40 +Found 1 PIN(s) +PIN Name +40414089 ASUS PIN + +``` +### Python module +Get all PINs for a single MAC +```python +>>> import wpspin +>>> generator = wpspin.WPSpin() +>>> generator.getAll('54:A0:50:75:D2:40') +[{'id': 'pin24', 'name': '24-bit PIN', 'pin': '77215369'}, {'id': 'pin28', 'name': '28-bit PIN', 'pin': '77215369'}, {'id': 'pin32', 'name': '32-bit PIN', 'pin': '98988167'}, {'id': 'pin36', 'name': '36-bit PIN', 'pin': '98988167'}, {'id': 'pin40', 'name': '40-bit PIN', 'pin': '46661760'}, {'id': 'pin44', 'name': '44-bit PIN', 'pin': '11772804'}, {'id': 'pin48', 'name': '48-bit PIN', 'pin': '13993603'}, {'id': 'pinDLink', 'name': 'D-Link PIN', 'pin': '76793011'}, {'id': 'pinDLink1', 'name': 'D-Link PIN +1', 'pin': '65690444'}, {'id': 'pinASUS', 'name': 'ASUS PIN', 'pin': '40414089'}, {'id': 'pinAirocon', 'name': 'Airocon Realtek', 'pin': '40774848'}, {'id': 'pinInvNIC', 'name': 'Inv NIC to PIN', 'pin': '90556791'}, {'id': 'pinNIC2', 'name': 'NIC * 2', 'pin': '54430723'}, {'id': 'pinNIC3', 'name': 'NIC * 3', 'pin': '31646086'}, {'id': 'pinOUIaddNIC', 'name': 'OUI + NIC', 'pin': '32676006'}, {'id': 'pinOUIsubNIC', 'name': 'OUI − NIC', 'pin': '78245280'}, {'id': 'pinOUIxorNIC', 'name': 'OUI ^ NIC', 'pin': '21918889'}, {'id': 'pinEmpty', 'name': 'Empty PIN', 'pin': ''}, {'id': 'pinCisco', 'name': 'Static PIN — Cisco', 'pin': '12345670'}, {'id': 'pinBrcm1', 'name': 'Static PIN — Broadcom 1', 'pin': '20172527'}, {'id': 'pinBrcm2', 'name': 'Static PIN — Broadcom 2', 'pin': '46264848'}, {'id': 'pinBrcm3', 'name': 'Static PIN — Broadcom 3', 'pin': '76229909'}, {'id': 'pinBrcm4', 'name': 'Static PIN — Broadcom 4', 'pin': '62327145'}, {'id': 'pinBrcm5', 'name': 'Static PIN — Broadcom 5', 'pin': '10864111'}, {'id': 'pinBrcm6', 'name': 'Static PIN — Broadcom 6', 'pin': '31957199'}, {'id': 'pinAirc1', 'name': 'Static PIN — Airocon 1', 'pin': '30432031'}, {'id': 'pinAirc2', 'name': 'Static PIN — Airocon 2', 'pin': '71412252'}, {'id': 'pinDSL2740R', 'name': 'Static PIN — DSL-2740R', 'pin': '68175542'}, {'id': 'pinRealtek1', 'name': 'Static PIN — Realtek 1', 'pin': '95661469'}, {'id': 'pinRealtek2', 'name': 'Static PIN — Realtek 2', 'pin': '95719115'}, {'id': 'pinRealtek3', 'name': 'Static PIN — Realtek 3', 'pin': '48563710'}, {'id': 'pinUpvel', 'name': 'Static PIN — Upvel', 'pin': '20854836'}, {'id': 'pinUR814AC', 'name': 'Static PIN — UR-814AC', 'pin': '43977680'}, {'id': 'pinUR825AC', 'name': 'Static PIN — UR-825AC', 'pin': '05294176'}, {'id': 'pinOnlime', 'name': 'Static PIN — Onlime', 'pin': '99956042'}, {'id': 'pinEdimax', 'name': 'Static PIN — Edimax', 'pin': '35611530'}, {'id': 'pinThomson', 'name': 'Static PIN — Thomson', 'pin': '67958146'}, {'id': 'pinHG532x', 'name': 'Static PIN — HG532x', 'pin': '34259283'}, {'id': 'pinH108L', 'name': 'Static PIN — H108L', 'pin': '94229882'}, {'id': 'pinONO', 'name': 'Static PIN — CBN ONO', 'pin': '95755212'}] +``` +or without static PINs +```python +>>> generator.getAll('54:A0:50:75:D2:40', get_static=False) +[{'id': 'pin24', 'name': '24-bit PIN', 'pin': '77215369'}, {'id': 'pin28', 'name': '28-bit PIN', 'pin': '77215369'}, {'id': 'pin32', 'name': '32-bit PIN', 'pin': '98988167'}, {'id': 'pin36', 'name': '36-bit PIN', 'pin': '98988167'}, {'id': 'pin40', 'name': '40-bit PIN', 'pin': '46661760'}, {'id': 'pin44', 'name': '44-bit PIN', 'pin': '11772804'}, {'id': 'pin48', 'name': '48-bit PIN', 'pin': '13993603'}, {'id': 'pinDLink', 'name': 'D-Link PIN', 'pin': '76793011'}, {'id': 'pinDLink1', 'name': 'D-Link PIN +1', 'pin': '65690444'}, {'id': 'pinASUS', 'name': 'ASUS PIN', 'pin': '40414089'}, {'id': 'pinAirocon', 'name': 'Airocon Realtek', 'pin': '40774848'}, {'id': 'pinInvNIC', 'name': 'Inv NIC to PIN', 'pin': '90556791'}, {'id': 'pinNIC2', 'name': 'NIC * 2', 'pin': '54430723'}, {'id': 'pinNIC3', 'name': 'NIC * 3', 'pin': '31646086'}, {'id': 'pinOUIaddNIC', 'name': 'OUI + NIC', 'pin': '32676006'}, {'id': 'pinOUIsubNIC', 'name': 'OUI − NIC', 'pin': '78245280'}, {'id': 'pinOUIxorNIC', 'name': 'OUI ^ NIC', 'pin': '21918889'}, {'id': 'pinEmpty', 'name': 'Empty PIN', 'pin': ''}] +``` +Get all PINs as list +```python +>>> generator.getList('54:A0:50:75:D2:40') +['77215369', '77215369', '98988167', '98988167', '46661760', '11772804', '13993603', '76793011', '65690444', '40414089', '40774848', '90556791', '54430723', '31646086', '32676006', '78245280', '21918889', '', '12345670', '20172527', '46264848', '76229909', '62327145', '10864111', '31957199', '30432031', '71412252', '68175542', '95661469', '95719115', '48563710', '20854836', '43977680', '05294176', '99956042', '35611530', '67958146', '34259283', '94229882', '95755212'] +``` +Get suggested PINs only +```python +>>> generator.getSuggested('54:A0:50:75:D2:40') +[{'id': 'pinASUS', 'name': 'ASUS PIN', 'pin': '40414089'}] +``` +or as list +```python +>>> generator.getSuggestedList('54:A0:50:75:D2:40') +['40414089'] +``` +Generate specific PIN for a single MAC +```python +>>> generator.generate('pin24', '54:A0:50:75:D2:40') +'77215369' +``` \ No newline at end of file diff --git a/WPSpin.py b/WPSpin.py deleted file mode 100644 index 2f2c0dd..0000000 --- a/WPSpin.py +++ /dev/null @@ -1,294 +0,0 @@ -# -*- coding: utf-8 -*- -class WPSException(Exception): - pass - - -class WPSpin(object): - '''WPS pin generator''' - def __init__(self): - self.ALGO_MAC = 0 - self.ALGO_EMPTY = 1 - self.ALGO_STATIC = 2 - - self.algos = {} - self.algos['pin24'] = {'name': '24-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin24} - self.algos['pin28'] = {'name': '28-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin28} - self.algos['pin32'] = {'name': '32-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin32} - self.algos['pin36'] = {'name': '36-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin36} - self.algos['pin40'] = {'name': '40-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin40} - self.algos['pin44'] = {'name': '44-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin44} - self.algos['pin48'] = {'name': '48-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin48} - self.algos['pinDLink'] = {'name': 'D-Link PIN', 'mode': self.ALGO_MAC, 'gen': self.pinDLink} - self.algos['pinDLink1'] = {'name': 'D-Link PIN +1', 'mode': self.ALGO_MAC, 'gen': self.pinDLink1} - self.algos['pinASUS'] = {'name': 'ASUS PIN', 'mode': self.ALGO_MAC, 'gen': self.pinASUS} - self.algos['pinAirocon'] = {'name': 'Airocon Realtek', 'mode': self.ALGO_MAC, 'gen': self.pinAirocon} - self.algos['pinInvNIC'] = {'name': 'Inv NIC to PIN', 'mode': self.ALGO_MAC, 'gen': self.pinInvNIC} - self.algos['pinNIC2'] = {'name': 'NIC * 2', 'mode': self.ALGO_MAC, 'gen': self.pinNIC2} - self.algos['pinNIC3'] = {'name': 'NIC * 3', 'mode': self.ALGO_MAC, 'gen': self.pinNIC3} - self.algos['pinOUIaddNIC'] = {'name': 'OUI + NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIaddNIC} - self.algos['pinOUIsubNIC'] = {'name': 'OUI − NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIsubNIC} - self.algos['pinOUIxorNIC'] = {'name': 'OUI ^ NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIxorNIC} - # Static pin algos - self.algos['pinEmpty'] = {'name': 'Empty PIN', 'mode': self.ALGO_EMPTY, 'gen': lambda mac: ''} - self.algos['pinCisco'] = {'name': 'Cisco', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 1234567} - self.algos['pinBrcm1'] = {'name': 'Broadcom 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 2017252} - self.algos['pinBrcm2'] = {'name': 'Broadcom 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4626484} - self.algos['pinBrcm3'] = {'name': 'Broadcom 3', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 7622990} - self.algos['pinBrcm4'] = {'name': 'Broadcom 4', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6232714} - self.algos['pinBrcm5'] = {'name': 'Broadcom 5', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 1086411} - self.algos['pinBrcm6'] = {'name': 'Broadcom 6', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3195719} - self.algos['pinAirc1'] = {'name': 'Airocon 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3043203} - self.algos['pinAirc2'] = {'name': 'Airocon 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 7141225} - self.algos['pinDSL2740R'] = {'name': 'DSL-2740R', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6817554} - self.algos['pinRealtek1'] = {'name': 'Realtek 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9566146} - self.algos['pinRealtek2'] = {'name': 'Realtek 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9571911} - self.algos['pinRealtek3'] = {'name': 'Realtek 3', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4856371} - self.algos['pinUpvel'] = {'name': 'Upvel', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 2085483} - self.algos['pinUR814AC'] = {'name': 'UR-814AC', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4397768} - self.algos['pinUR825AC'] = {'name': 'UR-825AC', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 529417} - self.algos['pinOnlime'] = {'name': 'Onlime', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9995604} - self.algos['pinEdimax'] = {'name': 'Edimax', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3561153} - self.algos['pinThomson'] = {'name': 'Thomson', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6795814} - self.algos['pinHG532x'] = {'name': 'HG532x', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3425928} - self.algos['pinH108L'] = {'name': 'H108L', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9422988} - self.algos['pinONO'] = {'name': 'CBN ONO', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9575521} - - def _parseMAC(self, mac): - mac = mac.replace(':', '').replace('-', '').replace('.', '') - mac = int(mac, 16) - return mac - - def _parseOUI(self, mac): - mac = mac.replace(':', '').replace('-', '').replace('.', '') - oui = int(mac[:6], 16) - return oui - - def checksum(self, pin): - ''' - Standard WPS checksum algorithm. - @pin — A 7 digit pin to calculate the checksum for. - Returns the checksum value. - ''' - accum = 0 - while pin: - accum += (3 * (pin % 10)) - pin = int(pin / 10) - accum += (pin % 10) - pin = int(pin / 10) - return ((10 - accum % 10) % 10) - - def generate(self, algo, mac): - ''' - WPS pin generator - @algo — the WPS pin algorithm ID - Returns the WPS pin string value - ''' - mac = self._parseMAC(mac) - if algo not in self.algos: - raise WPSException('Invalid WPS pin algorithm') - pin = self.algos[algo]['gen'](mac) - if algo == 'pinEmpty': - return pin - pin = pin % 10000000 - pin = str(pin) + str(self.checksum(pin)) - return pin.zfill(8) - - def getAll(self, mac, get_static=True): - ''' - Get all WPS pin's for single MAC - ''' - res = [] - for ID, algo in self.algos.items(): - if algo['mode'] == self.ALGO_STATIC and not get_static: - continue - item = {} - item['id'] = ID - if algo['mode'] == self.ALGO_STATIC: - item['name'] = 'Static PIN — ' + algo['name'] - else: - item['name'] = algo['name'] - item['pin'] = self.generate(ID, mac) - res.append(item) - return res - - def getList(self, mac, get_static=True): - ''' - Get all WPS pin's for single MAC as list - ''' - res = [] - for ID, algo in self.algos.items(): - if algo['mode'] == self.ALGO_STATIC and not get_static: - continue - res.append(self.generate(ID, mac)) - return res - - def getSuggested(self, mac): - ''' - Get all suggested WPS pin's for single MAC - ''' - algos = self.suggest(mac) - res = [] - for ID in algos: - algo = self.algos[ID] - item = {} - item['id'] = ID - if algo['mode'] == self.ALGO_STATIC: - item['name'] = 'Static PIN — ' + algo['name'] - else: - item['name'] = algo['name'] - item['pin'] = self.generate(ID, mac) - res.append(item) - return res - - def getSuggestedList(self, mac): - ''' - Get all suggested WPS pin's for single MAC as list - ''' - algos = self.suggest(mac) - res = [] - for algo in algos: - res.append(self.generate(algo, mac)) - return res - - def suggest(self, mac): - ''' - Get algos suggestions for single MAC - Returns the algo ID - ''' - oui = self._parseOUI(mac) - algorithms = { - 'pin24': (3318, 5329, 7391, 7967, 8821, 8951, 9819, 9934, 26187, 40998, 45068, 57376, 311149, 528501, 555596, 558651, 941390, 1080303, 1354211, 1358184, 1365581, 1867493, 2099437, 2108353, 2150192, 2631773, 2762845, 3180336, 3322588, 3435475, 3455642, 3676006, 4213251, 5021439, 5041630, 5135694, 5269488, 6048937, 6071197, 6091947, 6431549, 6438116, 6438399, 6443988, 6444444, 6450131, 6454622, 6461119, 6465764, 6469254, 6471791, 6473247, 6473492, 6474664, 6475198, 6482043, 6559472, 6582274, 6862543, 6954343, 6955837, 6957149, 6962687, 6968276, 6968732, 6974419, 6978910, 6985407, 6990052, 6996079, 6997535, 6997780, 6998952, 6999486, 7000414, 7000423, 7478631, 7480125, 7486692, 7486975, 7492564, 7493020, 7498707, 7503198, 7509695, 7514340, 7520367, 7521823, 7522068, 7523240, 7523774, 7524702, 7530619, 7891593, 7900663, 8396546, 8702386, 8971179, 9329998, 9475300, 9496250, 10000337, 10548161, 11151453, 11552890, 11580124, 11683580, 11834446, 12325889, 12383877, 12888093, 13122101, 13134983, 13393230, 13524302, 13921884, 13942655, 14183657, 14216087, 14446916, 14696758, 14732110, 14827830, 14828534, 14974201, 15256877, 15345757, 15475517, 15483894, 15518512, 15614966, 15905500, 16031731, 16259687, 16302225, 16306449, 16545046, 16577832, 16708904), - 'pin28': (2100167, 4736763, 13920936, 16272063), - 'pin32': (1830, 1073899, 1097544, 1366761, 1859371, 2927397, 3179945, 3179945, 4779532, 5260893, 5506214, 8396546, 8398473, 9473400, 13131776, 14221027, 15256600, 16018692, 16550807), - 'pinDLink': (5329, 1365581, 1867493, 2625659, 8702386, 10529563, 12100486, 12624059, 13414997, 14216087, 16545046), - 'pinDLink1': (5329, 6375, 6491, 7408, 7768, 8593, 8880, 9217, 9818, 1365581, 1867493, 3409924, 6085016, 8702386, 12100486, 13155865, 13161379, 13414997), - 'pinASUS': (1830, 1830, 6012, 6012, 7846, 12367, 57420, 298296, 299558, 528503, 528504, 528505, 540253, 548974, 549478, 1080132, 1097544, 1098619, 1113837, 1367465, 1580664, 1852441, 1869612, 1881900, 2367687, 2391840, 2905820, 2927397, 2948513, 3168826, 3179945, 3681354, 3724615, 3939844, 4200062, 4256257, 4516317, 4779532, 5260893, 5530841, 5546064, 5552138, 5798889, 6309323, 6333516, 6345130, 6574462, 6609236, 7084431, 7107104, 7142841, 7359867, 7365304, 7655467, 7873711, 7885870, 7920031, 8136292, 8404829, 8692771, 8955590, 8968182, 9179348, 9209899, 9456970, 9466498, 9500242, 9763762, 10247310, 10492713, 10548161, 11073504, 11280907, 11312663, 11313683, 11562687, 12080400, 12119566, 12334080, 12359296, 12381819, 12624059, 12849909, 12888093, 13131776, 13144569, 13635289, 13637570, 13665456, 14176486, 14221027, 14696265, 14991085, 15242486, 15256600, 15473241, 15475328, 15486029, 15759705, 16001107, 16006753, 16018415, 16265956, 16296709, 16312579, 16550807), - 'pinAirocon': (1830, 2859, 3828, 4915, 6012, 6895, 57419, 135192, 528499, 528503, 1053678, 2927397, 7900244, 8404829, 9763762, 12359296, 16006753, 16550807), - 'pinEmpty': (3727, 19063, 825023, 1073899, 1097461, 1859371, 2159523, 2921855, 3427818, 3725359, 3971186, 5553747, 5821806, 6558572, 6856950, 7351842, 7380781, 7645070, 7648638, 7658202, 7897346, 7902388, 7902850, 8141139, 8398473, 8966772, 9201864, 9742263, 9966387, 10278467, 10529563, 11330069, 13160798, 13280102, 13656204, 13902114, 13918435, 13924074, 14704742, 14970643, 15475328), - 'pinCisco': (6699, 9356, 9752, 3427819, 7369148, 14707093, 14732110), - 'pinBrcm1': (6825, 1315915, 9997149, 11334111, 12383877, 13161379, 15491684), - 'pinBrcm2': (1365581, 1867493, 2625659, 8702386, 12100486, 12383877, 13155865), - 'pinBrcm3': (1365581, 1867493, 2625659, 8127308, 12100486, 12383877, 13155865), - 'pinBrcm4': (1365581, 1597996, 1867493, 2117247, 2625659, 4986859, 8127448, 8702386, 12100486, 12383877, 13155865, 13161379, 13414997, 14183657, 16545046), - 'pinBrcm5': (1365581, 1597996, 1867493, 2117247, 2625659, 4986859, 8127448, 8702386, 12100486, 12383877, 13155865, 13161379, 13414997, 14183657, 16545046), - 'pinBrcm6': (1365581, 1597996, 1867493, 2117247, 2625659, 4986859, 8127448, 8702386, 12100486, 12383877, 13155865, 13161379, 13414997, 14183657, 16545046), - 'pinAirc1': (1580664, 4256257, 4516317, 13665456), - 'pinAirc2': (8692771, 8955590, 9179348), - 'pinDSL2740R': (9818, 1883577, 3409924, 6085016, 8702386, 16545046), - 'pinRealtek1': (3138, 3816, 5329), - 'pinRealtek2': (29283, 14991085), - 'pinRealtek3': (575155,), - 'pinUpvel': (16302225,), - 'pinUR814AC': (13942655,), - 'pinUR825AC': (13942655,), - 'pinOnlime': (5329, 7881846, 13942655, 16302225), - 'pinEdimax': (57420, 8396546), - 'pinThomson': (9764, 4469448, 8976327, 13370362), - 'pinHG532x': (26187, 549729, 555596, 825023, 1358184, 2099437, 2386341, 3435475, 7891593, 8971179, 10273138, 11330069, 13410851, 13662901, 15256877, 16253203, 16268799), - 'pinH108L': (4983220, 5024778, 10277451, 11564501, 13132999, 14418574, 16566423), - 'pinONO': (6042939, 14439292) - } - res = [] - for ID, OUI in algorithms.items(): - if oui in OUI: - res.append(ID) - return res - - def pin24(self, mac): - return (mac & 0xFFFFFF) - - def pin28(self, mac): - return (mac & 0xFFFFFFF) - - def pin32(self, mac): - return (mac % 0x100000000) - - def pin36(self, mac): - return (mac % 0x1000000000) - - def pin40(self, mac): - return (mac % 0x10000000000) - - def pin44(self, mac): - return (mac % 0x100000000000) - - def pin48(self, mac): - return mac - - def pinDLink(self, mac): - # Get the NIC part - nic = mac & 0xFFFFFF - # Calculating pin - pin = nic ^ 0x55AA55 - pin ^= (((pin & 0xF) << 4) + - ((pin & 0xF) << 8) + - ((pin & 0xF) << 12) + - ((pin & 0xF) << 16) + - ((pin & 0xF) << 20)) - pin %= int(10e6) - if pin < int(10e5): - pin += ((pin % 9) * int(10e5)) + int(10e5) - return pin - - def pinDLink1(self, mac): - return self.pinDLink(mac + 1) - - def pinASUS(self, mac): - mac = hex(mac).split('x')[-1].upper().zfill(12) - b = [] - for i in range(0, 12, 2): - b.append(int(mac[i:i+2], 16)) - pin = '' - for i in range(7): - pin += str((b[i % 6] + b[5]) % (10 - (i + b[1] + b[2] + b[3] + b[4] + b[5]) % 7)) - return int(pin) - - def pinAirocon(self, mac): - mac = hex(mac).split('x')[-1].upper().zfill(12) - b = [] - for i in range(0, 12, 2): - b.append(int(mac[i:i+2], 16)) - pin = ((b[0] + b[1]) % 10)\ - + (((b[5] + b[0]) % 10) * 10)\ - + (((b[4] + b[5]) % 10) * 100)\ - + (((b[3] + b[4]) % 10) * 1000)\ - + (((b[2] + b[3]) % 10) * 10000)\ - + (((b[1] + b[2]) % 10) * 100000)\ - + (((b[0] + b[1]) % 10) * 1000000) - return pin - - def pinInvNIC(self, mac): - nic = mac & 0xFFFFFF - pin = ~nic & 0xFFFFFF - return pin - - def pinNIC2(self, mac): - nic = mac & 0xFFFFFF - pin = nic * 2 - return pin - - def pinNIC3(self, mac): - nic = mac & 0xFFFFFF - pin = nic * 3 - return pin - - def pinOUIaddNIC(self, mac): - mac = hex(mac).split('x')[-1].upper().zfill(12) - oui = int(mac[:6], 16) - nic = int(mac[6:], 16) - pin = (oui + nic) % int(10e6) - return pin - - def pinOUIsubNIC(self, mac): - mac = hex(mac).split('x')[-1].upper().zfill(12) - oui = int(mac[:6], 16) - nic = int(mac[6:], 16) - pin = oui - nic if nic < oui else (oui + int(10e6) - nic) & 0xFFFFFF - return pin - - def pinOUIxorNIC(self, mac): - mac = hex(mac).split('x')[-1].upper().zfill(12) - oui = int(mac[:6], 16) - nic = int(mac[6:], 16) - pin = oui ^ nic - return pin diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e8e448c --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +from io import open +from setuptools import setup + +""" +:authors: drygdryg +:license: MIT +:copyright: (c) 2020 drygdryg +""" + +version = '0.1' + +with open('README.md', encoding='utf-8') as f: + long_description = f.read() + +setup( + name='wpspin', + version=version, + description='WPS PIN generator written in Python 3', + long_description=long_description, + long_description_content_type='text/markdown', + license='MIT', + + author='drygdryg', + author_email='drygdryg2014@yandex.com', + url='https://github.com/drygdryg/wpspin', + download_url='https://github.com/drygdryg/wpspin/archive/v{}.zip'.format(version), + + keywords='wireless wifi wpa wps generator pin code', + + packages=['wpspin'], + python_requires='>=3.4', + entry_points={ + 'console_scripts': [ + 'wpspin = wpspin.wpspin:main' + ] + }, + + classifiers=[ + 'License :: OSI Approved :: MIT License', + 'Environment :: Console', + 'Topic :: Security', + 'Topic :: Utilities', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + ] +) diff --git a/wpspin/__init__.py b/wpspin/__init__.py new file mode 100644 index 0000000..89dcde3 --- /dev/null +++ b/wpspin/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +:authors: drygdryg +:license: MIT +:copyright: (c) 2020 drygdryg +""" +from .wpspin import WPSpin + +__author__ = 'drygdryg' +__version__ = '0.1' diff --git a/wpspin/wpspin.py b/wpspin/wpspin.py new file mode 100644 index 0000000..d6569ec --- /dev/null +++ b/wpspin/wpspin.py @@ -0,0 +1,377 @@ +# -*- coding: utf-8 -*- +class NetworkAddress(): + def __init__(self, mac): + if isinstance(mac, int): + self._int_repr = mac + self._str_repr = self._int2mac(mac) + elif isinstance(mac, str): + self._str_repr = mac.replace('-', ':').replace('.', ':').upper() + self._int_repr = self._mac2int(mac) + else: + raise ValueError('MAC address must be string or integer') + + @property + def string(self): + return self._str_repr + + @string.setter + def string(self, value): + self._str_repr = value + self._int_repr = self._mac2int(value) + + @property + def integer(self): + return self._int_repr + + @integer.setter + def integer(self, value): + self._int_repr = value + self._str_repr = self._int2mac(value) + + def __int__(self): + return self.integer + + def __str__(self): + return self.string + + def __iadd__(self, other): + self.integer += other + + def __isub__(self, other): + self.integer -= other + + def __eq__(self, other): + return self.integer == other.integer + + def __ne__(self, other): + return self.integer != other.integer + + def __lt__(self, other): + return self.integer < other.integer + + def __gt__(self, other): + return self.integer > other.integer + + def _mac2int(self, mac): + return int(mac.replace(':', ''), 16) + + def _int2mac(self, mac): + mac = hex(mac).split('x')[-1].upper() + mac = mac.zfill(12) + mac = ':'.join(mac[i:i+2] for i in range(0, 12, 2)) + return mac + + def __repr__(self): + return 'NetworkAddress(string={}, integer={})'.format( + self._str_repr, self._int_repr) + + +class WPSpin(): + '''WPS pin generator''' + def __init__(self): + self.ALGO_MAC = 0 + self.ALGO_EMPTY = 1 + self.ALGO_STATIC = 2 + + self.algos = {} + self.algos['pin24'] = {'name': '24-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin24} + self.algos['pin28'] = {'name': '28-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin28} + self.algos['pin32'] = {'name': '32-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin32} + self.algos['pin36'] = {'name': '36-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin36} + self.algos['pin40'] = {'name': '40-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin40} + self.algos['pin44'] = {'name': '44-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin44} + self.algos['pin48'] = {'name': '48-bit PIN', 'mode': self.ALGO_MAC, 'gen': self.pin48} + self.algos['pinDLink'] = {'name': 'D-Link PIN', 'mode': self.ALGO_MAC, 'gen': self.pinDLink} + self.algos['pinDLink1'] = {'name': 'D-Link PIN +1', 'mode': self.ALGO_MAC, 'gen': self.pinDLink1} + self.algos['pinASUS'] = {'name': 'ASUS PIN', 'mode': self.ALGO_MAC, 'gen': self.pinASUS} + self.algos['pinAirocon'] = {'name': 'Airocon Realtek', 'mode': self.ALGO_MAC, 'gen': self.pinAirocon} + self.algos['pinInvNIC'] = {'name': 'Inv NIC to PIN', 'mode': self.ALGO_MAC, 'gen': self.pinInvNIC} + self.algos['pinNIC2'] = {'name': 'NIC * 2', 'mode': self.ALGO_MAC, 'gen': self.pinNIC2} + self.algos['pinNIC3'] = {'name': 'NIC * 3', 'mode': self.ALGO_MAC, 'gen': self.pinNIC3} + self.algos['pinOUIaddNIC'] = {'name': 'OUI + NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIaddNIC} + self.algos['pinOUIsubNIC'] = {'name': 'OUI − NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIsubNIC} + self.algos['pinOUIxorNIC'] = {'name': 'OUI ^ NIC', 'mode': self.ALGO_MAC, 'gen': self.pinOUIxorNIC} + # Static pin algos + self.algos['pinEmpty'] = {'name': 'Empty PIN', 'mode': self.ALGO_EMPTY, 'gen': lambda mac: ''} + self.algos['pinCisco'] = {'name': 'Cisco', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 1234567} + self.algos['pinBrcm1'] = {'name': 'Broadcom 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 2017252} + self.algos['pinBrcm2'] = {'name': 'Broadcom 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4626484} + self.algos['pinBrcm3'] = {'name': 'Broadcom 3', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 7622990} + self.algos['pinBrcm4'] = {'name': 'Broadcom 4', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6232714} + self.algos['pinBrcm5'] = {'name': 'Broadcom 5', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 1086411} + self.algos['pinBrcm6'] = {'name': 'Broadcom 6', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3195719} + self.algos['pinAirc1'] = {'name': 'Airocon 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3043203} + self.algos['pinAirc2'] = {'name': 'Airocon 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 7141225} + self.algos['pinDSL2740R'] = {'name': 'DSL-2740R', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6817554} + self.algos['pinRealtek1'] = {'name': 'Realtek 1', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9566146} + self.algos['pinRealtek2'] = {'name': 'Realtek 2', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9571911} + self.algos['pinRealtek3'] = {'name': 'Realtek 3', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4856371} + self.algos['pinUpvel'] = {'name': 'Upvel', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 2085483} + self.algos['pinUR814AC'] = {'name': 'UR-814AC', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 4397768} + self.algos['pinUR825AC'] = {'name': 'UR-825AC', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 529417} + self.algos['pinOnlime'] = {'name': 'Onlime', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9995604} + self.algos['pinEdimax'] = {'name': 'Edimax', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3561153} + self.algos['pinThomson'] = {'name': 'Thomson', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 6795814} + self.algos['pinHG532x'] = {'name': 'HG532x', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 3425928} + self.algos['pinH108L'] = {'name': 'H108L', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9422988} + self.algos['pinONO'] = {'name': 'CBN ONO', 'mode': self.ALGO_STATIC, 'gen': lambda mac: 9575521} + + def checksum(self, pin): + ''' + Standard WPS checksum algorithm. + @pin — A 7 digit pin to calculate the checksum for. + Returns the checksum value. + ''' + accum = 0 + while pin: + accum += (3 * (pin % 10)) + pin = int(pin / 10) + accum += (pin % 10) + pin = int(pin / 10) + return ((10 - accum % 10) % 10) + + def generate(self, algo, mac): + ''' + WPS pin generator + @algo — the WPS pin algorithm ID + Returns the WPS pin string value + ''' + mac = NetworkAddress(mac) + if algo not in self.algos: + raise ValueError('Invalid WPS pin algorithm') + pin = self.algos[algo]['gen'](mac) + if algo == 'pinEmpty': + return pin + pin = pin % 10000000 + pin = str(pin) + str(self.checksum(pin)) + return pin.zfill(8) + + def getAll(self, mac, get_static=True): + ''' + Get all WPS pin's for single MAC + ''' + res = [] + for ID, algo in self.algos.items(): + if algo['mode'] == self.ALGO_STATIC and not get_static: + continue + item = {} + item['id'] = ID + if algo['mode'] == self.ALGO_STATIC: + item['name'] = 'Static PIN — ' + algo['name'] + else: + item['name'] = algo['name'] + item['pin'] = self.generate(ID, mac) + res.append(item) + return res + + def getList(self, mac, get_static=True): + ''' + Get all WPS pin's for single MAC as list + ''' + res = [] + for ID, algo in self.algos.items(): + if algo['mode'] == self.ALGO_STATIC and not get_static: + continue + res.append(self.generate(ID, mac)) + return res + + def getSuggested(self, mac): + ''' + Get all suggested WPS pin's for single MAC + ''' + algos = self._suggest(mac) + res = [] + for ID in algos: + algo = self.algos[ID] + item = {} + item['id'] = ID + if algo['mode'] == self.ALGO_STATIC: + item['name'] = 'Static PIN — ' + algo['name'] + else: + item['name'] = algo['name'] + item['pin'] = self.generate(ID, mac) + res.append(item) + return res + + def getSuggestedList(self, mac): + ''' + Get all suggested WPS pin's for single MAC as list + ''' + algos = self._suggest(mac) + res = [] + for algo in algos: + res.append(self.generate(algo, mac)) + return res + + def _suggest(self, mac): + ''' + Get algos suggestions for single MAC + Returns the algo ID + ''' + mac = mac.replace(':', '').upper() + algorithms = { + 'pin24': ('04BF6D', '0E5D4E', '107BEF', '14A9E3', '28285D', '2A285D', '32B2DC', '381766', '404A03', '4E5D4E', '5067F0', '5CF4AB', '6A285D', '8E5D4E', 'AA285D', 'B0B2DC', 'C86C87', 'CC5D4E', 'CE5D4E', 'EA285D', 'E243F6', 'EC43F6', 'EE43F6', 'F2B2DC', 'FCF528', 'FEF528', '4C9EFF', '0014D1', 'D8EB97', '1C7EE5', '84C9B2', 'FC7516', '14D64D', '9094E4', 'BCF685', 'C4A81D', '00664B', '087A4C', '14B968', '2008ED', '346BD3', '4CEDDE', '786A89', '88E3AB', 'D46E5C', 'E8CD2D', 'EC233D', 'ECCB30', 'F49FF3', '20CF30', '90E6BA', 'E0CB4E', 'D4BF7F4', 'F8C091', '001CDF', '002275', '08863B', '00B00C', '081075', 'C83A35', '0022F7', '001F1F', '00265B', '68B6CF', '788DF7', 'BC1401', '202BC1', '308730', '5C4CA9', '62233D', '623CE4', '623DFF', '6253D4', '62559C', '626BD3', '627D5E', '6296BF', '62A8E4', '62B686', '62C06F', '62C61F', '62C714', '62CBA8', '62CDBE', '62E87B', '6416F0', '6A1D67', '6A233D', '6A3DFF', '6A53D4', '6A559C', '6A6BD3', '6A96BF', '6A7D5E', '6AA8E4', '6AC06F', '6AC61F', '6AC714', '6ACBA8', '6ACDBE', '6AD15E', '6AD167', '721D67', '72233D', '723CE4', '723DFF', '7253D4', '72559C', '726BD3', '727D5E', '7296BF', '72A8E4', '72C06F', '72C61F', '72C714', '72CBA8', '72CDBE', '72D15E', '72E87B', '0026CE', '9897D1', 'E04136', 'B246FC', 'E24136', '00E020', '5CA39D', 'D86CE9', 'DC7144', '801F02', 'E47CF9', '000CF6', '00A026', 'A0F3C1', '647002', 'B0487A', 'F81A67', 'F8D111', '34BA9A', 'B4944E'), + 'pin28': ('200BC7', '4846FB', 'D46AA8', 'F84ABF'), + 'pin32': ('000726', 'D8FEE3', 'FC8B97', '1062EB', '1C5F2B', '48EE0C', '802689', '908D78', 'E8CC18', '2CAB25', '10BF48', '14DAE9', '3085A9', '50465D', '5404A6', 'C86000', 'F46D04', '3085A9', '801F02'), + 'pinDLink': ('14D64D', '1C7EE5', '28107B', '84C9B2', 'A0AB1B', 'B8A386', 'C0A0BB', 'CCB255', 'FC7516', '0014D1', 'D8EB97'), + 'pinDLink1': ('0018E7', '00195B', '001CF0', '001E58', '002191', '0022B0', '002401', '00265A', '14D64D', '1C7EE5', '340804', '5CD998', '84C9B2', 'B8A386', 'C8BE19', 'C8D3A3', 'CCB255', '0014D1'), + 'pinASUS': ('049226', '04D9F5', '08606E', '0862669', '107B44', '10BF48', '10C37B', '14DDA9', '1C872C', '1CB72C', '2C56DC', '2CFDA1', '305A3A', '382C4A', '38D547', '40167E', '50465D', '54A050', '6045CB', '60A44C', '704D7B', '74D02B', '7824AF', '88D7F6', '9C5C8E', 'AC220B', 'AC9E17', 'B06EBF', 'BCEE7B', 'C860007', 'D017C2', 'D850E6', 'E03F49', 'F0795978', 'F832E4', '00072624', '0008A1D3', '00177C', '001EA6', '00304FB', '00E04C0', '048D38', '081077', '081078', '081079', '083E5D', '10FEED3C', '181E78', '1C4419', '2420C7', '247F20', '2CAB25', '3085A98C', '3C1E04', '40F201', '44E9DD', '48EE0C', '5464D9', '54B80A', '587BE906', '60D1AA21', '64517E', '64D954', '6C198F', '6C7220', '6CFDB9', '78D99FD', '7C2664', '803F5DF6', '84A423', '88A6C6', '8C10D4', '8C882B00', '904D4A', '907282', '90F65290', '94FBB2', 'A01B29', 'A0F3C1E', 'A8F7E00', 'ACA213', 'B85510', 'B8EE0E', 'BC3400', 'BC9680', 'C891F9', 'D00ED90', 'D084B0', 'D8FEE3', 'E4BEED', 'E894F6F6', 'EC1A5971', 'EC4C4D', 'F42853', 'F43E61', 'F46BEF', 'F8AB05', 'FC8B97', '7062B8', '78542E', 'C0A0BB8C', 'C412F5', 'C4A81D', 'E8CC18', 'EC2280', 'F8E903F4'), + 'pinAirocon': ('0007262F', '000B2B4A', '000EF4E7', '001333B', '00177C', '001AEF', '00E04BB3', '02101801', '0810734', '08107710', '1013EE0', '2CAB25C7', '788C54', '803F5DF6', '94FBB2', 'BC9680', 'F43E61', 'FC8B97'), + 'pinEmpty': ('E46F13', 'EC2280', '58D56E', '1062EB', '10BEF5', '1C5F2B', '802689', 'A0AB1B', '74DADA', '9CD643', '68A0F6', '0C96BF', '20F3A3', 'ACE215', 'C8D15E', '000E8F', 'D42122', '3C9872', '788102', '7894B4', 'D460E3', 'E06066', '004A77', '2C957F', '64136C', '74A78E', '88D274', '702E22', '74B57E', '789682', '7C3953', '8C68C8', 'D476EA', '344DEA', '38D82F', '54BE53', '709F2D', '94A7B7', '981333', 'CAA366', 'D0608C'), + 'pinCisco': ('001A2B', '00248C', '002618', '344DEB', '7071BC', 'E06995', 'E0CB4E', '7054F5'), + 'pinBrcm1': ('ACF1DF', 'BCF685', 'C8D3A3', '988B5D', '001AA9', '14144B', 'EC6264'), + 'pinBrcm2': ('14D64D', '1C7EE5', '28107B', '84C9B2', 'B8A386', 'BCF685', 'C8BE19'), + 'pinBrcm3': ('14D64D', '1C7EE5', '28107B', 'B8A386', 'BCF685', 'C8BE19', '7C034C'), + 'pinBrcm4': ('14D64D', '1C7EE5', '28107B', '84C9B2', 'B8A386', 'BCF685', 'C8BE19', 'C8D3A3', 'CCB255', 'FC7516', '204E7F', '4C17EB', '18622C', '7C03D8', 'D86CE9'), + 'pinBrcm5': ('14D64D', '1C7EE5', '28107B', '84C9B2', 'B8A386', 'BCF685', 'C8BE19', 'C8D3A3', 'CCB255', 'FC7516', '204E7F', '4C17EB', '18622C', '7C03D8', 'D86CE9'), + 'pinBrcm6': ('14D64D', '1C7EE5', '28107B', '84C9B2', 'B8A386', 'BCF685', 'C8BE19', 'C8D3A3', 'CCB255', 'FC7516', '204E7F', '4C17EB', '18622C', '7C03D8', 'D86CE9'), + 'pinAirc1': ('181E78', '40F201', '44E9DD', 'D084B0'), + 'pinAirc2': ('84A423', '8C10D4', '88A6C6'), + 'pinDSL2740R': ('00265A', '1CBDB9', '340804', '5CD998', '84C9B2', 'FC7516'), + 'pinRealtek1': ('0014D1', '000C42', '000EE8'), + 'pinRealtek2': ('007263', 'E4BEED'), + 'pinRealtek3': ('08C6B3',), + 'pinUpvel': ('784476', 'D4BF7F0', 'F8C091'), + 'pinUR814AC': ('D4BF7F60',), + 'pinUR825AC': ('D4BF7F5',), + 'pinOnlime': ('D4BF7F', 'F8C091', '144D67', '784476', '0014D1'), + 'pinEdimax': ('801F02', '00E04C'), + 'pinThomson': ('002624', '4432C8', '88F7C7', 'CC03FA'), + 'pinHG532x': ('00664B', '086361', '087A4C', '0C96BF', '14B968', '2008ED', '2469A5', '346BD3', '786A89', '88E3AB', '9CC172', 'ACE215', 'D07AB5', 'CCA223', 'E8CD2D', 'F80113', 'F83DFF'), + 'pinH108L': ('4C09B4', '4CAC0A', '84742A4', '9CD24B', 'B075D5', 'C864C7', 'DC028E', 'FCC897'), + 'pinONO': ('5C353B', 'DC537C') + } + res = [] + for algo_id, masks in algorithms.items(): + if mac.startswith(masks): + res.append(algo_id) + return res + + def pin24(self, mac): + return (mac.integer & 0xFFFFFF) + + def pin28(self, mac): + return (mac.integer & 0xFFFFFFF) + + def pin32(self, mac): + return (mac.integer % 0x100000000) + + def pin36(self, mac): + return (mac.integer % 0x1000000000) + + def pin40(self, mac): + return (mac.integer % 0x10000000000) + + def pin44(self, mac): + return (mac.integer % 0x100000000000) + + def pin48(self, mac): + return mac.integer + + def pinDLink(self, mac): + # Get the NIC part + nic = mac.integer & 0xFFFFFF + # Calculating pin + pin = nic ^ 0x55AA55 + pin ^= (((pin & 0xF) << 4) + + ((pin & 0xF) << 8) + + ((pin & 0xF) << 12) + + ((pin & 0xF) << 16) + + ((pin & 0xF) << 20)) + pin %= int(10e6) + if pin < int(10e5): + pin += ((pin % 9) * int(10e5)) + int(10e5) + return pin + + def pinDLink1(self, mac): + mac.integer += 1 + return self.pinDLink(mac) + + def pinASUS(self, mac): + b = [int(i, 16) for i in mac.string.split(':')] + pin = '' + for i in range(7): + pin += str((b[i % 6] + b[5]) % (10 - (i + b[1] + b[2] + b[3] + b[4] + b[5]) % 7)) + return int(pin) + + def pinAirocon(self, mac): + b = [int(i, 16) for i in mac.string.split(':')] + pin = ((b[0] + b[1]) % 10)\ + + (((b[5] + b[0]) % 10) * 10)\ + + (((b[4] + b[5]) % 10) * 100)\ + + (((b[3] + b[4]) % 10) * 1000)\ + + (((b[2] + b[3]) % 10) * 10000)\ + + (((b[1] + b[2]) % 10) * 100000)\ + + (((b[0] + b[1]) % 10) * 1000000) + return pin + + def pinInvNIC(self, mac): + nic = mac.integer & 0xFFFFFF + pin = ~nic & 0xFFFFFF + return pin + + def pinNIC2(self, mac): + nic = mac.integer & 0xFFFFFF + pin = nic * 2 + return pin + + def pinNIC3(self, mac): + nic = mac.integer & 0xFFFFFF + pin = nic * 3 + return pin + + def pinOUIaddNIC(self, mac): + mac = mac.string.replace(':', '') + oui = int(mac[:6], 16) + nic = int(mac[6:], 16) + pin = (oui + nic) % int(10e6) + return pin + + def pinOUIsubNIC(self, mac): + mac = mac.string.replace(':', '') + oui = int(mac[:6], 16) + nic = int(mac[6:], 16) + pin = oui - nic if nic < oui else (oui + int(10e6) - nic) & 0xFFFFFF + return pin + + def pinOUIxorNIC(self, mac): + mac = mac.string.replace(':', '') + oui = int(mac[:6], 16) + nic = int(mac[6:], 16) + pin = oui ^ nic + return pin + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description='WPS PIN generator written in Python 3', + epilog='Example: %(prog)s 11:22:33:44:55:66' + ) + parser.add_argument( + 'mac', + type=str, + help='target MAC address to generate PIN code. Example: 11:22:33:44:55:66' + ) + parser.add_argument( + '-A', '--get-all', + action='store_true', + help='get all PIN codes in addition to the suggested ones for a single MAC' + ) + + args = parser.parse_args() + + pinGen = WPSpin() + if args.get_all: + pins = pinGen.getAll(args.mac) + else: + pins = pinGen.getSuggested(args.mac) + + if pins: + print('Found {} PIN(s)'.format(len(pins))) + print('{:<10} {}'.format('PIN', 'Name')) + for pin in pins: + print('{:<10} {}'.format(pin['pin'], pin['name'])) + else: + print('No PINs found — try to get all PINs (-A)')