From 7758dcb27383aba06662231404e447212c3f5fcb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 9 Dec 2005 23:25:22 +0000 Subject: [PATCH] 2005-12-09 Dan Williams * libnm-util/* configure.in Makefile.am - Add a utility library for clients of NetworkManager. It's only targetted at applets for the moment, and contains a generalized 802.11 cipher framework for different types of keys (WEP & WPA Hex, ASCII, Passphrase) git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1152 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 10 + Makefile.am | 2 +- configure.in | 6 + libnm-util/Makefile.am | 48 ++ libnm-util/cipher-manager.c | 59 +++ libnm-util/cipher-manager.h | 35 ++ libnm-util/cipher-private.h | 54 ++ libnm-util/cipher-wep-ascii.c | 108 ++++ libnm-util/cipher-wep-ascii.h | 28 + libnm-util/cipher-wep-hex.c | 164 ++++++ libnm-util/cipher-wep-hex.h | 28 + libnm-util/cipher-wep-passphrase.c | 144 ++++++ libnm-util/cipher-wep-passphrase.h | 28 + libnm-util/cipher-wpa-psk-hex.c | 109 ++++ libnm-util/cipher-wpa-psk-hex.h | 29 ++ libnm-util/cipher-wpa-psk-passphrase.c | 70 +++ libnm-util/cipher-wpa-psk-passphrase.h | 27 + libnm-util/cipher.c | 107 ++++ libnm-util/cipher.h | 38 ++ libnm-util/gnome-keyring-md5.c | 291 +++++++++++ libnm-util/gnome-keyring-md5.h | 22 + libnm-util/libnm-util.pc.in | 13 + libnm-util/sha1.c | 691 +++++++++++++++++++++++++ libnm-util/sha1.h | 34 ++ 24 files changed, 2144 insertions(+), 1 deletion(-) create mode 100644 libnm-util/Makefile.am create mode 100644 libnm-util/cipher-manager.c create mode 100644 libnm-util/cipher-manager.h create mode 100644 libnm-util/cipher-private.h create mode 100644 libnm-util/cipher-wep-ascii.c create mode 100644 libnm-util/cipher-wep-ascii.h create mode 100644 libnm-util/cipher-wep-hex.c create mode 100644 libnm-util/cipher-wep-hex.h create mode 100644 libnm-util/cipher-wep-passphrase.c create mode 100644 libnm-util/cipher-wep-passphrase.h create mode 100644 libnm-util/cipher-wpa-psk-hex.c create mode 100644 libnm-util/cipher-wpa-psk-hex.h create mode 100644 libnm-util/cipher-wpa-psk-passphrase.c create mode 100644 libnm-util/cipher-wpa-psk-passphrase.h create mode 100644 libnm-util/cipher.c create mode 100644 libnm-util/cipher.h create mode 100644 libnm-util/gnome-keyring-md5.c create mode 100644 libnm-util/gnome-keyring-md5.h create mode 100644 libnm-util/libnm-util.pc.in create mode 100644 libnm-util/sha1.c create mode 100644 libnm-util/sha1.h diff --git a/ChangeLog b/ChangeLog index fa5f2fa3a6..b5a49f6acb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-12-09 Dan Williams + + * libnm-util/* + configure.in + Makefile.am + - Add a utility library for clients of NetworkManager. It's + only targetted at applets for the moment, and contains + a generalized 802.11 cipher framework for different + types of keys (WEP & WPA Hex, ASCII, Passphrase) + 2005-12-09 Robert Love * src/NetworkManagerDevice.c: handle error better in diff --git a/Makefile.am b/Makefile.am index e903c35401..c58b843d63 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = utils src dispatcher-daemon gnome initscript test po include +SUBDIRS = utils src dispatcher-daemon gnome initscript test po include libnm-util EXTRA_DIST = \ CONTRIBUTING \ diff --git a/configure.in b/configure.in index d89e01f77e..c993cb548a 100644 --- a/configure.in +++ b/configure.in @@ -127,6 +127,10 @@ PKG_CHECK_MODULES(GTHREAD, gthread-2.0) AC_SUBST(GTHREAD_CFLAGS) AC_SUBST(GTHREAD_LIBS) +PKG_CHECK_MODULES(GLIB, glib-2.0) +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + PKG_CHECK_MODULES(GMODULE, gmodule-2.0) AC_SUBST(GMODULE_CFLAGS) AC_SUBST(GMODULE_LIBS) @@ -287,6 +291,8 @@ src/named-manager/Makefile src/vpn-manager/Makefile src/dhcp-manager/Makefile src/backends/Makefile +libnm-util/libnm-util.pc +libnm-util/Makefile dispatcher-daemon/Makefile gnome/Makefile gnome/applet/Makefile diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am new file mode 100644 index 0000000000..15500c3392 --- /dev/null +++ b/libnm-util/Makefile.am @@ -0,0 +1,48 @@ +INCLUDES = -I${top_srcdir} -I${top_srcdir}/include + +lib_LTLIBRARIES=libnm-util.la + +libnm_util_la_CPPFLAGS = $(GLIB_CFLAGS) + +if WITH_GCRYPT +libnm_util_la_CPPFLAGS += $(LIBGCRYPT_CFLAGS) +endif + +libnm_util_la_SOURCES= \ + cipher.c \ + cipher.h \ + cipher-manager.c \ + cipher-manager.h \ + cipher-wep-hex.c \ + cipher-wep-hex.h \ + cipher-wep-passphrase.c \ + cipher-wep-passphrase.h \ + cipher-wep-ascii.c \ + cipher-wep-ascii.h \ + cipher-wpa-psk-hex.c \ + cipher-wpa-psk-hex.h \ + cipher-wpa-psk-passphrase.c \ + cipher-wpa-psk-passphrase.h \ + sha1.c \ + sha1.h + +if !WITH_GCRYPT +libnm_util_la_SOURCES += gnome-keyring-md5.c gnome-keyring-md5.h +endif + +libnm_util_la_LDFLAGS= $(GLIB_LIBS) + +if WITH_GCRYPT +libnm_util_la_LDFLAGS += $(LIBGCRYPT_LIBS) +endif + +libnm_util_includedir=$(includedir)/NetworkManager + +libnm_util_include_HEADERS = cipher-manager.h cipher.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libnm-util.pc + +DISTCLEANFILES = libnm-util.pc + +EXTRA_DIST = libnm-util.pc.in diff --git a/libnm-util/cipher-manager.c b/libnm-util/cipher-manager.c new file mode 100644 index 0000000000..8df98b9a52 --- /dev/null +++ b/libnm-util/cipher-manager.c @@ -0,0 +1,59 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-manager.h" +#include "cipher.h" + +struct CipherManager +{ + GSList * ciphers; +}; + + +/* Singleton instance of the Cipher Manager */ +static CipherManager * cipher_manager = NULL; + + +CipherManager * cipher_manager_get_instance (void) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + g_static_mutex_lock (&mutex); + if (!cipher_manager) + cipher_manager = g_malloc0 (sizeof (CipherManager)); + g_static_mutex_unlock (&mutex); + + return cipher_manager; +} + +int cipher_manager_register_cipher (CipherManager *cm, IEEE_802_11_Cipher *cipher) +{ + g_return_val_if_fail (cm != NULL, -1); + g_return_val_if_fail (cipher != NULL, -1); + + ieee_802_11_cipher_ref (cipher); + cm->ciphers = g_slist_prepend (cm->ciphers, cipher); + + return 0; +} diff --git a/libnm-util/cipher-manager.h b/libnm-util/cipher-manager.h new file mode 100644 index 0000000000..0be8b95df1 --- /dev/null +++ b/libnm-util/cipher-manager.h @@ -0,0 +1,35 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_MANAGER_H +#define CIPHER_MANAGER_H + +#include "cipher.h" + +typedef struct CipherManager CipherManager; + + +CipherManager * cipher_manager_get_instance (void); + +int cipher_manager_register_cipher (CipherManager *cm, IEEE_802_11_Cipher *cipher); + + +#endif /* CIPHER_MANAGER_H */ diff --git a/libnm-util/cipher-private.h b/libnm-util/cipher-private.h new file mode 100644 index 0000000000..e77f9e1356 --- /dev/null +++ b/libnm-util/cipher-private.h @@ -0,0 +1,54 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_PRIVATE_H +#define CIPHER_PRIVATE_H + +struct IEEE_802_11_Cipher +{ + int refcount; + + /* From /usr/include/wireless.h, IW_AUTH_CIPHER_* value + * corresponding to this encryption method, + * ex IW_AUTH_CIPHER_WEP104 + */ + int we_cipher; + + /* Min & max lengths of user-input for this cipher method */ + int input_min; + int input_max; + + /* Secret hash function, if any. Takes user-entered + * password/passphrase/key and returns binary key to be + * sent to the card's driver itself. Returns an allocated + * value the the caller must free. + */ + char * (*cipher_hash_func)(IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + /* Input validation function, if any. Takes a user-entered + * password/passphrase/key and determines whether it is valid + * for this cipher. Return 0 if valid, -1 if invalid. + */ + int (*cipher_input_validate_func)(IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); +}; + + +#endif /* CIPHER_PRIVATE_H */ diff --git a/libnm-util/cipher-wep-ascii.c b/libnm-util/cipher-wep-ascii.c new file mode 100644 index 0000000000..84d0b1d5e9 --- /dev/null +++ b/libnm-util/cipher-wep-ascii.c @@ -0,0 +1,108 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-wep-ascii.h" +#include "cipher.h" +#include "cipher-private.h" +#include "cipher-manager.h" +#ifdef HAVE_GCRYPT +#include +#else +#include "gnome-keyring-md5.h" +#endif + + +static char * cipher_wep128_ascii_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); +static char * cipher_wep64_ascii_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + +static char * cipher_wep_ascii_hash_func (IEEE_802_11_Cipher *cipher, const char *input, int req_keylen) +{ + int keylen; + char * ret = NULL; + + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + g_return_val_if_fail (req_keylen > 0, NULL); + + keylen = strlen (input); + if (keylen != req_keylen) + return NULL; + + if (keylen > IW_ENCODING_TOKEN_MAX) + keylen = IW_ENCODING_TOKEN_MAX; + ret = g_malloc0 (keylen+1); + memcpy (ret, input, keylen); + + return ret; +} + + +#define WEP128_ASCII_INPUT_SIZE 13 +int cipher_wep128_ascii_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP104; + cipher->input_min = WEP128_ASCII_INPUT_SIZE; + cipher->input_max = WEP128_ASCII_INPUT_SIZE; + cipher->cipher_hash_func = cipher_wep128_ascii_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep128_ascii_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_ascii_hash_func (cipher, input, WEP128_ASCII_INPUT_SIZE); +} + + +#define WEP64_ASCII_INPUT_SIZE 5 +int cipher_wep64_ascii_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP40; + cipher->input_min = WEP64_ASCII_INPUT_SIZE; + cipher->input_max = WEP64_ASCII_INPUT_SIZE; + cipher->cipher_hash_func = cipher_wep64_ascii_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep64_ascii_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_ascii_hash_func (cipher, input, WEP64_ASCII_INPUT_SIZE); +} + diff --git a/libnm-util/cipher-wep-ascii.h b/libnm-util/cipher-wep-ascii.h new file mode 100644 index 0000000000..a67cbaf312 --- /dev/null +++ b/libnm-util/cipher-wep-ascii.h @@ -0,0 +1,28 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_WEP_ASCII_H +#define CIPHER_WEP_ASCII_H + +int cipher_wep128_ascii_register (void); +int cipher_wep64_ascii_register (void); + +#endif /* CIPHER_WEP_ASCII_H */ diff --git a/libnm-util/cipher-wep-hex.c b/libnm-util/cipher-wep-hex.c new file mode 100644 index 0000000000..0a4c505d10 --- /dev/null +++ b/libnm-util/cipher-wep-hex.c @@ -0,0 +1,164 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-wep-hex.h" +#include "cipher.h" +#include "cipher-private.h" +#include "cipher-manager.h" + + +static char * cipher_wep128_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); +static char * cipher_wep64_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + +static char * cipher_wep_hex_convert_func (IEEE_802_11_Cipher *cipher, const char *input, int req_keylen) +{ + const char * p; + gboolean success = TRUE; + int keylen = 0; + int dlen; /* Digits sequence length */ + GString * hashed = NULL; + char * ret = NULL; + + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + g_return_val_if_fail (req_keylen > 0, NULL); + + hashed = g_string_sized_new (32); + + /* Code here is mostly ripped from wireless-tools */ + + /* Third case : as hexadecimal digits */ + p = input; + dlen = -1; + + /* Loop until we run out of chars in input or overflow the output */ + while (*p != '\0') + { + int temph; + int templ; + int count; + + /* No more chars in this sequence */ + if (dlen <= 0) + { + /* Skip separator */ + if (dlen == 0) + p++; + /* Calculate num of char to next separator */ + dlen = strcspn (p, "-:;.,"); + if (!dlen) + continue; + } + + /* Get each char separatly (and not by two) so that we don't + * get confused by 'enc' (=> '0E'+'0C') and similar */ + count = sscanf (p, "%1X%1X", &temph, &templ); + if (count < 1) + { + success = FALSE; + break; /* Error -> non-hex char */ + } + + /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/ + if (dlen % 2) + count = 1; + + /* Put back two chars as one byte and output */ + if (count == 2) + templ |= temph << 4; + else + templ = temph; + g_string_append_c (hashed, (unsigned char) (templ & 0xFF)); + + /* Check overflow in output */ + if (hashed->len >= IW_ENCODING_TOKEN_MAX) + break; + + /* Move on to next chars */ + p += count; + keylen += count; + dlen -= count; + } + + /* Ensure the actual key data length is what's required */ + if (keylen != req_keylen) + success = FALSE; + + if (success) + ret = hashed->str; + + /* Don't free the string data if conversion was successful */ + g_string_free (hashed, (success == TRUE ? FALSE : TRUE)); + + return ret; +} + + +#define WEP128_HEX_INPUT_SIZE 26 +int cipher_wep128_hex_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP104; + cipher->input_min = WEP128_HEX_INPUT_SIZE; + cipher->input_max = WEP128_HEX_INPUT_SIZE; + cipher->cipher_hash_func = cipher_wep128_hex_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep128_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_hex_convert_func (cipher, input, WEP128_HEX_INPUT_SIZE); +} + + +#define WEP64_HEX_INPUT_SIZE 10 +int cipher_wep64_hex_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP40; + cipher->input_min = WEP64_HEX_INPUT_SIZE; + cipher->input_max = WEP64_HEX_INPUT_SIZE; + cipher->cipher_hash_func = cipher_wep64_hex_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep64_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_hex_convert_func (cipher, input, WEP64_HEX_INPUT_SIZE); +} diff --git a/libnm-util/cipher-wep-hex.h b/libnm-util/cipher-wep-hex.h new file mode 100644 index 0000000000..c9d79ac301 --- /dev/null +++ b/libnm-util/cipher-wep-hex.h @@ -0,0 +1,28 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_WEP_HEX_H +#define CIPHER_WEP_HEX_H + +int cipher_wep128_hex_register (void); +int cipher_wep64_hex_register (void); + +#endif /* CIPHER_WEP_HEX_H */ diff --git a/libnm-util/cipher-wep-passphrase.c b/libnm-util/cipher-wep-passphrase.c new file mode 100644 index 0000000000..43c7a20604 --- /dev/null +++ b/libnm-util/cipher-wep-passphrase.c @@ -0,0 +1,144 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-wep-passphrase.h" +#include "cipher.h" +#include "cipher-private.h" +#include "cipher-manager.h" +#ifdef HAVE_GCRYPT +#include +#else +#include "gnome-keyring-md5.h" +#endif + + +static char * cipher_wep128_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); +static char * cipher_wep64_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + +/* + * cipher_wep_passphrase_ascii_to_hex + * + * Convert an ascii string into a suitable string for use + * as a WEP key. + * + * Code originally by Alex Larsson and + * copyright Red Hat, Inc. under terms of the LGPL. + * + */ +static char * cipher_wep_passphrase_ascii_to_hex (const unsigned char *ascii, int req_keylen) +{ + static char hex_digits[] = "0123456789abcdef"; + unsigned char *res; + int i; + + g_return_val_if_fail (ascii != NULL, NULL); + g_return_val_if_fail ((req_keylen == 26) || (req_keylen == 10), NULL); + + res = g_malloc (33); + for (i = 0; i < 16; i++) + { + res[2*i] = hex_digits[(ascii[i] >> 4) & 0xf]; + res[2*i+1] = hex_digits[ascii[i] & 0xf]; + } + /* Cut converted key off at the correct length for this cipher type */ + res[req_keylen] = 0; + + return res; +} + +static char * cipher_wep_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *input, int req_keylen) +{ + char md5_data[65]; + unsigned char digest[16]; + int input_len; + int i; + + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + input_len = strlen (input); + if (input_len < 1) + return NULL; + + /* Get at least 64 bits */ + for (i = 0; i < 64; i++) + md5_data [i] = input [i % input_len]; + + /* Null terminate md5 seed data and hash it */ + md5_data[64] = 0; +#ifdef HAVE_GCRYPT + gcry_md_hash_buffer (GCRY_MD_MD5, digest, md5_data, 64); +#else + gnome_keyring_md5_string (md5_data, digest); +#endif + + return (cipher_wep_passphrase_ascii_to_hex (digest, req_keylen)); +} + + +int cipher_wep128_passphrase_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP104; + cipher->input_min = 0; /* What _is_ the min, really? */ + cipher->input_max = 64; + cipher->cipher_hash_func = cipher_wep128_passphrase_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep128_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_passphrase_hash_func (cipher, input, 26); +} + +int cipher_wep64_passphrase_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_WEP40; + cipher->input_min = 1; /* What _is_ the min, really? */ + cipher->input_max = 64; + cipher->cipher_hash_func = cipher_wep64_passphrase_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wep64_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + return cipher_wep_passphrase_hash_func (cipher, input, 10); +} + diff --git a/libnm-util/cipher-wep-passphrase.h b/libnm-util/cipher-wep-passphrase.h new file mode 100644 index 0000000000..083203bb64 --- /dev/null +++ b/libnm-util/cipher-wep-passphrase.h @@ -0,0 +1,28 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_WEP_PASSPHRASE_H +#define CIPHER_WEP_PASSPHRASE_H + +int cipher_wep128_passphrase_register (void); +int cipher_wep64_passphrase_register (void); + +#endif /* CIPHER_WEP_PASSPHRASE_H */ diff --git a/libnm-util/cipher-wpa-psk-hex.c b/libnm-util/cipher-wpa-psk-hex.c new file mode 100644 index 0000000000..fa0caf7891 --- /dev/null +++ b/libnm-util/cipher-wpa-psk-hex.c @@ -0,0 +1,109 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-wpa-psk-hex.h" +#include "cipher.h" +#include "cipher-private.h" +#include "cipher-manager.h" + + +static char * cipher_wpa_psk_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + +/* From hostap, Copyright (c) 2002-2005, Jouni Malinen */ + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + +static int hexstr2bin(const char *hex, char *buf, size_t len) +{ + size_t i; + int a; + const char *ipos = hex; + char *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) + return -1; + *opos++ = a; + ipos += 2; + } + return 0; +} + +/* End from hostap */ + +int cipher_wpa_psk_hex_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_TKIP; + cipher->input_min = 2; + cipher->input_max = WPA_PMK_LEN * 2; + cipher->cipher_hash_func = cipher_wpa_psk_hex_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wpa_psk_hex_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + char * buf = NULL; + char * ret = NULL; + int err = -1; + + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + + buf = g_malloc0 (WPA_PMK_LEN+1); + err = hexstr2bin (input, buf, WPA_PMK_LEN); + if (err != 0) + g_free (buf); + else + ret = buf; + + return ret; +} diff --git a/libnm-util/cipher-wpa-psk-hex.h b/libnm-util/cipher-wpa-psk-hex.h new file mode 100644 index 0000000000..e3350bafd3 --- /dev/null +++ b/libnm-util/cipher-wpa-psk-hex.h @@ -0,0 +1,29 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_WPA_PSK_HEX_H +#define CIPHER_WPA_PSK_HEX_H + +#define WPA_PMK_LEN 32 + +int cipher_wpa_psk_hex_register (void); + +#endif /* CIPHER_WPA_PSK_HEX_H */ diff --git a/libnm-util/cipher-wpa-psk-passphrase.c b/libnm-util/cipher-wpa-psk-passphrase.c new file mode 100644 index 0000000000..3f373177ce --- /dev/null +++ b/libnm-util/cipher-wpa-psk-passphrase.c @@ -0,0 +1,70 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include + +#include "cipher-wpa-psk-passphrase.h" +#include "cipher-wpa-psk-hex.h" +#include "cipher.h" +#include "cipher-private.h" +#include "cipher-manager.h" +#include "sha1.h" + + +static char * cipher_wpa_psk_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + + +/* From hostap, Copyright (c) 2002-2005, Jouni Malinen */ + +/* End from hostap */ + +int cipher_wpa_psk_passphrase_register (void) +{ + CipherManager * cm = cipher_manager_get_instance (); + IEEE_802_11_Cipher * cipher = g_malloc0 (sizeof (IEEE_802_11_Cipher)); + + cipher->we_cipher = IW_AUTH_CIPHER_TKIP; + cipher->input_min = 8; + cipher->input_max = WPA_PMK_LEN * 2; + cipher->cipher_hash_func = cipher_wpa_psk_passphrase_hash_func; + cipher->cipher_input_validate_func = cipher_default_validate_func; + + return cipher_manager_register_cipher (cm, cipher); +} + +static char * cipher_wpa_psk_passphrase_hash_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + int ssid_len; + char *buf = NULL; + + g_return_val_if_fail (cipher != NULL, NULL); + g_return_val_if_fail (input != NULL, NULL); + g_return_val_if_fail (ssid != NULL, NULL); + + ssid_len = strlen (ssid); + g_return_val_if_fail (ssid_len > 0, NULL); + + buf = g_malloc0 (WPA_PMK_LEN * 2); + pbkdf2_sha1 (input, (char *) ssid, ssid_len, 4096, buf, WPA_PMK_LEN); + + return buf; +} diff --git a/libnm-util/cipher-wpa-psk-passphrase.h b/libnm-util/cipher-wpa-psk-passphrase.h new file mode 100644 index 0000000000..64076360ff --- /dev/null +++ b/libnm-util/cipher-wpa-psk-passphrase.h @@ -0,0 +1,27 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_WPA_PSK_PASSPHRASE_H +#define CIPHER_WPA_PSK_PASSPHRASE_H + +int cipher_wpa_psk_passphrase_register (void); + +#endif /* CIPHER_WPA_PSK_PASSPHRASE_H */ diff --git a/libnm-util/cipher.c b/libnm-util/cipher.c new file mode 100644 index 0000000000..2d35a5abf1 --- /dev/null +++ b/libnm-util/cipher.c @@ -0,0 +1,107 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#include +#include +#include + +#include "cipher.h" +#include "cipher-private.h" + + +void ieee_802_11_cipher_ref (IEEE_802_11_Cipher *cipher) +{ + g_return_if_fail (cipher != NULL); + + cipher->refcount++; +} + +void ieee_802_11_cipher_unref (IEEE_802_11_Cipher *cipher) +{ + g_return_if_fail (cipher != NULL); + + cipher->refcount--; + if (cipher->refcount <= 0) + { + memset (cipher, 0, sizeof (IEEE_802_11_Cipher)); + g_free (cipher); + } +} + +int ieee_802_11_cipher_get_we_cipher (IEEE_802_11_Cipher *cipher) +{ + g_return_val_if_fail (cipher != NULL, -1); + + return cipher->we_cipher; +} + +int ieee_802_11_cipher_get_input_min (IEEE_802_11_Cipher *cipher) +{ + g_return_val_if_fail (cipher != NULL, -1); + + return cipher->input_min; +} + +int ieee_802_11_cipher_get_input_max (IEEE_802_11_Cipher *cipher) +{ + g_return_val_if_fail (cipher != NULL, -1); + + return cipher->input_max; +} + +char *ieee_802_11_cipher_hash (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, NULL); + + return (*cipher->cipher_hash_func)(cipher, ssid, input); +} + +int ieee_802_11_cipher_validate (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + g_return_val_if_fail (cipher != NULL, -1); + + if (!cipher->cipher_input_validate_func) + return cipher_default_validate_func (cipher, ssid, input); + + return (*cipher->cipher_input_validate_func)(cipher, ssid, input); +} + + +int cipher_default_validate_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input) +{ + char * hashed = NULL; + int ret = -1; + int len; + + g_return_val_if_fail (cipher != NULL, -1); + g_return_val_if_fail (input != NULL, -1); + + len = strlen (input); + if ((len < cipher->input_min) || (len > cipher->input_max)) + return -1; + + hashed = (*cipher->cipher_hash_func)(cipher, ssid, input); + if (hashed) + ret = 0; + g_free (hashed); + + return ret; +} diff --git a/libnm-util/cipher.h b/libnm-util/cipher.h new file mode 100644 index 0000000000..b14357597d --- /dev/null +++ b/libnm-util/cipher.h @@ -0,0 +1,38 @@ +/* NetworkManager Wireless Applet -- Display wireless access points and allow user control + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef CIPHER_H +#define CIPHER_H + +typedef struct IEEE_802_11_Cipher IEEE_802_11_Cipher; + +void ieee_802_11_cipher_ref (IEEE_802_11_Cipher *cipher); +void ieee_802_11_cipher_unref (IEEE_802_11_Cipher *cipher); +int ieee_802_11_cipher_get_we_cipher (IEEE_802_11_Cipher *cipher); +int ieee_802_11_cipher_get_input_min (IEEE_802_11_Cipher *cipher); +int ieee_802_11_cipher_get_input_max (IEEE_802_11_Cipher *cipher); +char * ieee_802_11_cipher_hash (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); +int ieee_802_11_cipher_validate (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + +/* For use by ciphers themselves */ +int cipher_default_validate_func (IEEE_802_11_Cipher *cipher, const char *ssid, const char *input); + +#endif /* CIPHER_H */ diff --git a/libnm-util/gnome-keyring-md5.c b/libnm-util/gnome-keyring-md5.c new file mode 100644 index 0000000000..0a3dd71dc0 --- /dev/null +++ b/libnm-util/gnome-keyring-md5.c @@ -0,0 +1,291 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * GnomeKeyringMD5Context structure, pass it to gnome_keyring_md5_init, call + * gnome_keyring_md5_update as needed on buffers full of bytes, and then call + * gnome_keyring_md5_final, which will fill a supplied 32-byte array with the + * digest in ascii form. + * + */ + +#include "gnome-keyring-md5.h" +#include + +static void gnome_keyring_md5_transform (guint32 buf[4], + guint32 const in[16]); + +void +gnome_keyring_md5_string (const char *string, unsigned char digest[16]) +{ + struct GnomeKeyringMD5Context md5_context; + + gnome_keyring_md5_init (&md5_context); + gnome_keyring_md5_update (&md5_context, (const unsigned char *)string, strlen (string)); + gnome_keyring_md5_final (digest, &md5_context); +} + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else + +/* + * Note: this code is harmless on little-endian machines. + */ +static void +byteReverse(unsigned char *buf, unsigned longs) +{ + guint32 t; + do { + t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(guint32 *) buf = t; + buf += 4; + } while (--longs); +} + +#endif + +char * +gnome_keyring_md5_digest_to_ascii (unsigned char digest[16]) +{ + static char hex_digits[] = "0123456789abcdef"; + char *res; + int i; + + res = g_malloc (33); + + for (i = 0; i < 16; i++) { + res[2*i] = hex_digits[digest[i] >> 4]; + res[2*i+1] = hex_digits[digest[i] & 0xf]; + } + + res[32] = 0; + + return res; +} + + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +gnome_keyring_md5_init (struct GnomeKeyringMD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +gnome_keyring_md5_update (struct GnomeKeyringMD5Context *ctx, + unsigned char const *buf, + unsigned len) +{ + guint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((guint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy (p, buf, len); + return; + } + memcpy (p, buf, t); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy (ctx->in, buf, 64); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +gnome_keyring_md5_final (unsigned char digest[16], struct GnomeKeyringMD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset (p, 0, count); + byteReverse (ctx->in, 16); + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((guint32 *) ctx->in)[14] = ctx->bits[0]; + ((guint32 *) ctx->in)[15] = ctx->bits[1]; + + gnome_keyring_md5_transform (ctx->buf, (guint32 *) ctx->in); + byteReverse ((unsigned char *) ctx->buf, 4); + memcpy (digest, ctx->buf, 16); + memset (ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1 (z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define gnome_keyring_md5_step(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. GnomeKeyringMD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +gnome_keyring_md5_transform (guint32 buf[4], guint32 const in[16]) +{ + register guint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + gnome_keyring_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + gnome_keyring_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); + gnome_keyring_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); + gnome_keyring_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); + gnome_keyring_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + gnome_keyring_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + gnome_keyring_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + gnome_keyring_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + gnome_keyring_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + gnome_keyring_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + gnome_keyring_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); + gnome_keyring_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + gnome_keyring_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + gnome_keyring_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + gnome_keyring_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + gnome_keyring_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + gnome_keyring_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + gnome_keyring_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + gnome_keyring_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + gnome_keyring_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + diff --git a/libnm-util/gnome-keyring-md5.h b/libnm-util/gnome-keyring-md5.h new file mode 100644 index 0000000000..f3fd5be560 --- /dev/null +++ b/libnm-util/gnome-keyring-md5.h @@ -0,0 +1,22 @@ +#ifndef GNOME_KEYRING_MD5_H +#define GNOME_KEYRING_MD5_H + +#include + +struct GnomeKeyringMD5Context { + guint32 buf[4]; + guint32 bits[2]; + unsigned char in[64]; +}; + +char *gnome_keyring_md5_digest_to_ascii (unsigned char digest[16]); +void gnome_keyring_md5_string (const char *string, + unsigned char digest[16]); +void gnome_keyring_md5_init (struct GnomeKeyringMD5Context *ctx); +void gnome_keyring_md5_update (struct GnomeKeyringMD5Context *ctx, + unsigned char const *buf, + unsigned len); +void gnome_keyring_md5_final (unsigned char digest[16], + struct GnomeKeyringMD5Context *ctx); + +#endif /* GNOME_KEYRING_MD5_H */ diff --git a/libnm-util/libnm-util.pc.in b/libnm-util/libnm-util.pc.in new file mode 100644 index 0000000000..b148d5f0cb --- /dev/null +++ b/libnm-util/libnm-util.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libnm_util +Description: Convenience library for clients of NetworkManager +Version: @VERSION@ +Requires: glib-2.0 +Cflags: -I${includedir}/NetworkManager +Libs: -L${libdir} -lnm_util + + diff --git a/libnm-util/sha1.c b/libnm-util/sha1.c new file mode 100644 index 0000000000..11614f0f13 --- /dev/null +++ b/libnm-util/sha1.c @@ -0,0 +1,691 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include +#include + +#include "sha1.h" + + +/* Define types for stupid code. Userspace should + * be using u_*_t rather than kernel-space u* types. + */ +typedef u_int8_t u8; +typedef u_int16_t u16; +typedef u_int32_t u32; +typedef u_int64_t u64; + +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); +void sha1_transform(u8 *state, const u8 data[64]); + +void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + const u8 *addr[3]; + size_t len[3]; + addr[0] = key; + len[0] = key_len; + addr[1] = data; + len[1] = data_len; + addr[2] = key; + len[2] = key_len; + sha1_vector(3, addr, len, mac); +} + + +/* HMAC code is based on RFC 2104 */ +void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[20]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return; + } + + /* if key is longer than 64 bytes reset it to key = SHA1(key) */ + if (key_len > 64) { + sha1_vector(1, &key, &key_len, tk); + key = tk; + key_len = 20; + } + + /* the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + memset(k_pad, 0, sizeof(k_pad)); + memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + sha1_vector(1 + num_elem, _addr, _len, mac); + + memset(k_pad, 0, sizeof(k_pad)); + memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA1_MAC_LEN; + sha1_vector(2, _addr, _len, mac); +} + + +void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + + +void sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u8 zero = 0, counter = 0; + size_t pos, plen; + u8 hash[SHA1_MAC_LEN]; + size_t label_len = strlen(label); + const unsigned char *addr[4]; + size_t len[4]; + + addr[0] = (u8 *) label; + len[0] = label_len; + addr[1] = &zero; + len[1] = 1; + addr[2] = data; + len[2] = data_len; + addr[3] = &counter; + len[3] = 1; + + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + if (plen >= SHA1_MAC_LEN) { + hmac_sha1_vector(key, key_len, 4, addr, len, + &buf[pos]); + pos += SHA1_MAC_LEN; + } else { + hmac_sha1_vector(key, key_len, 4, addr, len, + hash); + memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } +} + + +static void pbkdf2_sha1_f(const char *passphrase, const char *ssid, + size_t ssid_len, int iterations, int count, + u8 *digest) +{ + unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; + int i, j; + unsigned char count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + size_t passphrase_len = strlen(passphrase); + + addr[0] = (u8 *) ssid; + len[0] = ssid_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + count_buf[0] = (count >> 24) & 0xff; + count_buf[1] = (count >> 16) & 0xff; + count_buf[2] = (count >> 8) & 0xff; + count_buf[3] = count & 0xff; + hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp); + memcpy(digest, tmp, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, + tmp2); + memcpy(tmp, tmp2, SHA1_MAC_LEN); + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } +} + + +void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + int count = 0; + unsigned char *pos = buf; + size_t left = buflen; + size_t plen; + unsigned char digest[SHA1_MAC_LEN]; + + while (left > 0) { + count++; + pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, + digest); + plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; + memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } +} + + +#ifndef EAP_TLS_FUNCS + +typedef struct { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +static void SHA1Init(SHA1_CTX *context); +static void SHA1Update(SHA1_CTX *context, const void *data, u32 len); +static void SHA1Final(unsigned char digest[20], SHA1_CTX* context); +static void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + */ +void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + SHA1_CTX ctx; + size_t i; + + SHA1Init(&ctx); + for (i = 0; i < num_elem; i++) + SHA1Update(&ctx, addr[i], len[i]); + SHA1Final(mac, &ctx); +} + + +/** + * sha1_transform - Perform one SHA-1 transform step + * @state: SHA-1 state + * @data: Input data for the SHA-1 transform + * + * This function is used to implement random number generation specified in + * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is + * similar to SHA-1, but has different message padding and as such, access to + * just part of the SHA-1 is needed. + */ +void sha1_transform(u8 *state, const u8 data[64]) +{ + SHA1Transform((u32 *) state, data); +} + + +/* ===== start - public domain SHA1 implementation ===== */ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 4/01 +By Jouni Malinen +Minor changes to match the coding style used in Dynamics. + +Modified September 24, 2004 +By Jouni Malinen +Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u32 state[5], const unsigned char buffer[64]) +{ + u32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + u32 l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + u32 workspace[16]; + block = (CHAR64LONG16 *) workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, 0, 64); +#endif +} + + +/* SHA1Init - Initialize new context */ + +static void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) +{ + u32 i, j; + const unsigned char *data = _data; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + u32 i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *) "\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *) "\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() + */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & + 255); + } + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); +} + +/* ===== end - public domain SHA1 implementation ===== */ + +#endif /* EAP_TLS_FUNCS */ + + +#ifdef TEST_MAIN + +static u8 key0[] = +{ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; +static u8 data0[] = "Hi There"; +static u8 prf0[] = +{ + 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84, + 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54, + 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06, + 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee, + 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88, + 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb, + 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e, + 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a +}; + +static u8 key1[] = "Jefe"; +static u8 data1[] = "what do ya want for nothing?"; +static u8 prf1[] = +{ + 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad, + 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4, + 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58, + 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09, + 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa, + 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02, + 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7, + 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc +}; + + +static u8 key2[] = +{ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa +}; +static u8 data2[] = +{ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; +static u8 prf2[] = +{ + 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f, + 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1, + 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1, + 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce, + 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc, + 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae, + 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6, + 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07 +}; + + +struct passphrase_test { + char *passphrase; + char *ssid; + char psk[32]; +}; + +static struct passphrase_test passphrase_tests[] = +{ + { + "password", + "IEEE", + { + 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef, + 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90, + 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2, + 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e + } + }, + { + "ThisIsAPassword", + "ThisIsASSID", + { + 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6, + 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3, + 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08, + 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf + } + }, + { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", + { + 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83, + 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c, + 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48, + 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62 + } + }, +}; + +#define NUM_PASSPHRASE_TESTS \ +(sizeof(passphrase_tests) / sizeof(passphrase_tests[0])) + + +int main(int argc, char *argv[]) +{ + u8 res[512]; + int ret = 0, i; + + printf("PRF-SHA1 test cases:\n"); + + sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1, + res, sizeof(prf0)); + if (memcmp(res, prf0, sizeof(prf0)) == 0) + printf("Test case 0 - OK\n"); + else { + printf("Test case 0 - FAILED!\n"); + ret++; + } + + sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1, + res, sizeof(prf1)); + if (memcmp(res, prf1, sizeof(prf1)) == 0) + printf("Test case 1 - OK\n"); + else { + printf("Test case 1 - FAILED!\n"); + ret++; + } + + sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2), + res, sizeof(prf2)); + if (memcmp(res, prf2, sizeof(prf2)) == 0) + printf("Test case 2 - OK\n"); + else { + printf("Test case 2 - FAILED!\n"); + ret++; + } + + ret += test_eap_fast(); + + printf("PBKDF2-SHA1 Passphrase test cases:\n"); + for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) { + u8 psk[32]; + struct passphrase_test *test = &passphrase_tests[i]; + pbkdf2_sha1(test->passphrase, + test->ssid, strlen(test->ssid), + 4096, psk, 32); + if (memcmp(psk, test->psk, 32) == 0) + printf("Test case %d - OK\n", i); + else { + printf("Test case %d - FAILED!\n", i); + ret++; + } + } + + return ret; +} +#endif /* TEST_MAIN */ diff --git a/libnm-util/sha1.h b/libnm-util/sha1.h new file mode 100644 index 0000000000..40863c860f --- /dev/null +++ b/libnm-util/sha1.h @@ -0,0 +1,34 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_H +#define SHA1_H + +#include + + +#define SHA1_MAC_LEN 20 + +void sha1_mac(const u_int8_t *key, size_t key_len, const u_int8_t *data, size_t data_len, + u_int8_t *mac); +void hmac_sha1_vector(const u_int8_t *key, size_t key_len, size_t num_elem, + const u_int8_t *addr[], const size_t *len, u_int8_t *mac); +void hmac_sha1(const u_int8_t *key, size_t key_len, const u_int8_t *data, size_t data_len, + u_int8_t *mac); +void sha1_prf(const u_int8_t *key, size_t key_len, const char *label, + const u_int8_t *data, size_t data_len, u_int8_t *buf, size_t buf_len); +void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u_int8_t *buf, size_t buflen); + +#endif /* SHA1_H */