From 9ae519fc410b8488c8445ab730babc086de08aec Mon Sep 17 00:00:00 2001 From: Mike Black W9MDB Date: Thu, 24 Feb 2022 17:13:18 -0600 Subject: [PATCH] Working on password access for rigctld -- not fully implmented yet Need to check on security audit and cross-platform compilation first https://github.com/Hamlib/Hamlib/issues/813 --- Makefile.am | 4 +- configure.ac | 1 + include/hamlib/rig.h | 3 + rigs/dummy/netrigctl.c | 12 + security/AESStringCrypt.c | 543 +++++++++++++++++++++++ security/AESStringCrypt.h | 110 +++++ security/Android.mk | 25 ++ security/Makefile.am | 13 + security/Makefile.nt | 36 ++ security/aes.c | 886 ++++++++++++++++++++++++++++++++++++++ security/aes.h | 24 ++ security/password.c | 85 ++++ security/password.h | 31 ++ security/sctest.c | 207 +++++++++ security/security.c | 60 +++ security/security.h | 2 + security/security_test.c | 104 +++++ security/sha256.c | 371 ++++++++++++++++ security/sha256.h | 24 ++ src/Makefile.am | 4 +- src/rig.c | 12 + tests/rigctl.c | 2 +- tests/rigctl_parse.c | 65 ++- tests/rigctl_parse.h | 2 +- tests/rigctld.c | 24 +- 25 files changed, 2624 insertions(+), 26 deletions(-) create mode 100644 security/AESStringCrypt.c create mode 100755 security/AESStringCrypt.h create mode 100644 security/Android.mk create mode 100644 security/Makefile.am create mode 100755 security/Makefile.nt create mode 100644 security/aes.c create mode 100755 security/aes.h create mode 100644 security/password.c create mode 100755 security/password.h create mode 100644 security/sctest.c create mode 100644 security/security.c create mode 100644 security/security.h create mode 100644 security/security_test.c create mode 100644 security/sha256.c create mode 100755 security/sha256.h diff --git a/Makefile.am b/Makefile.am index 520d758e4..807e278e5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,7 @@ EXTRA_DIST = PLAN LICENSE hamlib.m4 hamlib.pc.in README.developer \ doc_DATA = ChangeLog COPYING COPYING.LIB LICENSE \ README README.betatester README.developer -SUBDIRS = macros include lib \ +SUBDIRS = macros include lib security \ $(BACKEND_LIST) \ $(RIG_BACKEND_LIST) \ $(ROT_BACKEND_LIST) \ @@ -24,7 +24,7 @@ SUBDIRS = macros include lib \ ## Static list of distributed directories. DIST_SUBDIRS = macros include lib src c++ bindings tests doc android scripts rotators/indi simulators\ - $(BACKEND_LIST) $(RIG_BACKEND_LIST) $(ROT_BACKEND_LIST) $(AMP_BACKEND_LIST) + security $(BACKEND_LIST) $(RIG_BACKEND_LIST) $(ROT_BACKEND_LIST) $(AMP_BACKEND_LIST) # Install any third party macros into our tree for distribution ACLOCAL_AMFLAGS = -I macros --install diff --git a/configure.ac b/configure.ac index ef2ba34e1..afefa7de7 100644 --- a/configure.ac +++ b/configure.ac @@ -814,6 +814,7 @@ macros/Makefile include/Makefile lib/Makefile src/Makefile +security/Makefile c++/Makefile bindings/Makefile doc/Makefile diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index b645e77ca..cc1879a6d 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -2041,6 +2041,7 @@ struct rig_caps { // this will be used to check rigcaps structure is compatible with client char *hamlib_check_rig_caps; // a constant value we can check for hamlib integrity int (*get_conf2)(RIG *rig, token_t token, char *val, int val_len); + int (*password)(RIG *rig, unsigned char *key1, unsigned char *key2); /*< Send encrypted password if rigctld is secured with -A/--password */ }; //! @endcond @@ -3378,6 +3379,8 @@ extern HAMLIB_EXPORT(int) hl_usleep(rig_useconds_t msec); extern HAMLIB_EXPORT(int) rig_cookie(RIG *rig, enum cookie_e cookie_cmd, char *cookie, int cookie_len); +extern HAMLIB_EXPORT(int) rig_password(RIG *rig, const unsigned char *key1, const unsigned char *key2); + //extern HAMLIB_EXPORT(int) int longlat2locator HAMLIB_PARAMS((double longitude, double latitude, diff --git a/rigs/dummy/netrigctl.c b/rigs/dummy/netrigctl.c index 983ba117b..52c254f0b 100644 --- a/rigs/dummy/netrigctl.c +++ b/rigs/dummy/netrigctl.c @@ -2630,7 +2630,18 @@ static int netrigctl_power2mW(RIG *rig, unsigned int *mwpower, float power, RETURNFUNC(RIG_OK); } +int netrigctl_password(RIG *rig, unsigned char *key1, unsigned char *key2) +{ + char cmdbuf[256]; + char buf[256]; + int retval; + ENTERFUNC; + rig_debug(RIG_DEBUG_VERBOSE, "%s: key1=%s, key2=%s\n", __func__, key1, key2); + SNPRINTF(cmdbuf, sizeof(cmdbuf), "\\password %s\n", key1); + retval = netrigctl_transaction(rig, cmdbuf, strlen(cmdbuf), buf); + RETURNFUNC(retval); +} /* * Netrigctl rig capabilities. @@ -2746,6 +2757,7 @@ struct rig_caps netrigctl_caps = //.get_trn = netrigctl_get_trn, .power2mW = netrigctl_power2mW, .mW2power = netrigctl_mW2power, + .password = netrigctl_password, .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS }; diff --git a/security/AESStringCrypt.c b/security/AESStringCrypt.c new file mode 100644 index 000000000..efc8ab26c --- /dev/null +++ b/security/AESStringCrypt.c @@ -0,0 +1,543 @@ +/* + * AESStringCrypt.c + * + * AES String Crypt 1.1 + * Copyright (C) 2007, 2008, 2009, 2012, 2015 + * + * Author: Paul E. Jones + * + * This library will encrypt octet strings of the specified length up + * to ULLONG_MAX - 70 octet in length. If there is an error, the return + * value from the encryption or decryption function will be + * AESSTRINGCRYPT_ERROR. Any other value, including zero, is a valid + * length value. Note that an encrypted string can be up to 69 octets + * longer than the original plaintext string, thus the restriction on the + * input string size. + * + * The output of the string encryption function is a string that is + * compliant with the AES Crypt version 0 file format. For reference, + * see: https://www.aescrypt.com/aes_file_format.html. + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + */ + +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#include "AESStringCrypt.h" + +/* + * AESStringCrypt + * + * Description + * This function is called to encrypt the string "plaintext". + * The encrypted string is placed in "ciphertext". Note that + * the encrypted string is up to 68 bytes larger than the + * plaintext string. This is to accomodate the header defined + * by "AES Crypt File Format 0" and to store the last cipher + * block (which is padded to 16 octets). + * + * Parameters + * password [in] + * The password used to encrypt the string in UCS-16 + * format. + * password_length [in] + * The length of the password in octets + * plaintext [in] + * The plaintext string to be encrypted + * plaintext_length [in] + * The length of the plaintext string + * ciphertext [out] + * The encrypted string + * + * Returns + * Returns the length of the ciphertext string or AESSTRINGCRYPT_ERROR + * if there was an error when trying to encrypt the string. + */ +unsigned long long AESStringCrypt(unsigned char *password, + unsigned long password_length, + unsigned char *plaintext, + unsigned long long plaintext_length, + unsigned char *ciphertext) +{ + aes_context aes_ctx; + sha256_context sha_ctx; + sha256_t digest; + unsigned char IV[16]; + int i, n; + unsigned char buffer[32]; + unsigned char ipad[64], opad[64]; +#ifdef _WIN32 + HCRYPTPROV hProv; + DWORD result_code; +#else + time_t current_time; + pid_t process_id; + FILE *randfp = NULL; +#endif + unsigned char *p; + + /* + * Write an AES signature at the head of the file, along + * with the AES file format version number. + */ + ciphertext[0] = 'A'; + ciphertext[1] = 'E'; + ciphertext[2] = 'S'; + ciphertext[3] = 0x00; /* Version 0 */ + ciphertext[4] = (plaintext_length & 0x0F); + + /* + * We will use p as the pointer into the cipher + */ + p = ciphertext + 5; + +#ifdef _WIN32 + + /* + * Prepare for random number generation + */ + if (!CryptAcquireContext(&hProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + { + result_code = GetLastError(); + + if (GetLastError() == NTE_BAD_KEYSET) + { + if (!CryptAcquireContext(&hProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) + { + result_code = GetLastError(); + } + else + { + result_code = ERROR_SUCCESS; + } + } + + if (result_code != ERROR_SUCCESS) + { + return AESSTRINGCRYPT_ERROR; + } + } + + /* + * Create the 16-bit IV used for encrypting the plaintext. + * We do not fully trust the system's randomization functions, + * so we improve on that by also hashing the random octets + * and using only a portion of the hash. This IV + * generation could be replaced with any good random + * source of data. + */ + memset(IV, 0, 16); + memset(buffer, 0, 32); + + sha256_starts(&sha_ctx); + + for (i = 0; i < 256; i++) + { + if (!CryptGenRandom(hProv, + 32, + (BYTE *) buffer)) + { + CryptReleaseContext(hProv, 0); + return AESSTRINGCRYPT_ERROR; + } + + sha256_update(&sha_ctx, buffer, 32); + } + + sha256_finish(&sha_ctx, digest); + + /* + * We're finished collecting random data + */ + CryptReleaseContext(hProv, 0); + + /* + * Get the IV from the digest buffer + */ + memcpy(IV, digest, 16); + +#else + + /* + * Open the source for random data. Note that while the entropy + * might be lower with /dev/urandom than /dev/random, it will not + * fail to produce something. Also, we're going to hash the result + * anyway. + */ + if ((randfp = fopen("/dev/urandom", "r")) == NULL) + { + return AESSTRINGCRYPT_ERROR; + } + + /* + * We will use an initialization vector comprised of the current time + * process ID, and random data, all hashed together with SHA-256. + */ + current_time = time(NULL); + + for (i = 0; i < 8; i++) + { + buffer[i] = (unsigned char) + (current_time >> (i * 8)); + } + + process_id = getpid(); + + for (i = 0; i < 8; i++) + { + buffer[i + 8] = (unsigned char) + (process_id >> (i * 8)); + } + + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, buffer, 16); + + for (i = 0; i < 256; i++) + { + if (fread(buffer, 1, 32, randfp) != 32) + { + return AESSTRINGCRYPT_ERROR; + } + + sha256_update(&sha_ctx, + buffer, + 32); + } + + sha256_finish(&sha_ctx, digest); + + /* + * We're finished collecting random data + */ + fclose(randfp); + + /* + * Get the IV from the digest buffer + */ + memcpy(IV, digest, 16); +#endif + + /* + * Copy the IV to the ciphertext string + */ + memcpy(p, IV, 16); + p += 16; + + /* + * Hash the IV and password 8192 times + */ + memset(digest, 0, 32); + memcpy(digest, IV, 16); + + for (i = 0; i < 8192; i++) + { + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, digest, 32); + sha256_update(&sha_ctx, + password, + password_length); + sha256_finish(&sha_ctx, + digest); + } + + /* + * Set the AES encryption key + */ + aes_set_key(&aes_ctx, digest, 256); + + /* + * Set the ipad and opad arrays with values as + * per RFC 2104 (HMAC). HMAC is defined as + * H(K XOR opad, H(K XOR ipad, text)) + */ + memset(ipad, 0x36, 64); + memset(opad, 0x5C, 64); + + for (i = 0; i < 32; i++) + { + ipad[i] ^= digest[i]; + opad[i] ^= digest[i]; + } + + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, ipad, 64); + + while (plaintext_length > 0) + { + /* + * Grab the next block of plaintext + */ + if (plaintext_length >= 16) + { + n = 16; + } + else + { + n = (int) plaintext_length; + } + + plaintext_length -= n; + + memcpy(buffer, plaintext, n); + plaintext += n; + + /* + * XOR plain text block with previous encrypted + * output (i.e., use CBC) + */ + for (i = 0; i < 16; i++) + { + buffer[i] ^= IV[i]; + } + + /* + * Encrypt the contents of the buffer + */ + aes_encrypt(&aes_ctx, buffer, buffer); + + /* + * Concatenate the "text" as we compute the HMAC + */ + sha256_update(&sha_ctx, buffer, 16); + + /* + * Write the encrypted block + */ + memcpy(p, buffer, 16); + p += 16; + + /* + * Update the IV (CBC mode) + */ + memcpy(IV, buffer, 16); + } + + /* + * Write the HMAC + */ + sha256_finish(&sha_ctx, digest); + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, opad, 64); + sha256_update(&sha_ctx, digest, 32); + sha256_finish(&sha_ctx, digest); + memcpy(p, digest, 32); + p += 32; + + return (p - ciphertext); +} + +/* + * AESStringDecrypt + * + * Description + * This function is called to decrypt the string "ciphertext". + * The decrypted string is placed in "plaintext". + * + * Parameters + * password [in] + * The password used to encrypt the string in UCS-16 + * format. + * password_length [in] + * The length of the password in octets + * ciphertext [in] + * The ciphertext string to be decrypted + * ciphertext_length [in] + * The length of the ciphertext string + * plaintext [out] + * The decrypted string + * + * Returns + * Returns the length of the plaintext string or AESSTRINGCRYPT_ERROR + * if there was an error when trying to encrypt the string. + */ +unsigned long long AESStringDecrypt(unsigned char *password, + unsigned long password_length, + unsigned char *ciphertext, + unsigned long long ciphertext_length, + unsigned char *plaintext) +{ + aes_context aes_ctx; + sha256_context sha_ctx; + sha256_t digest; + unsigned char IV[16]; + int i, n; + unsigned char buffer[64], buffer2[32]; + unsigned char ipad[64], opad[64]; + unsigned char *p; + int final_block_size; + + /* + * Encrypted strings will be at least 53 octets in length + * and the rest must be a multiple of 16 octets + */ + if (ciphertext_length < 53) + { + return AESSTRINGCRYPT_ERROR; + } + + if (!(ciphertext[0] == 'A' && ciphertext[1] == 'E' && + ciphertext[2] == 'S')) + { + return AESSTRINGCRYPT_ERROR; + } + + /* + * Validate the version number and take any version-specific actions + */ + if (ciphertext[3] > 0) + { + return AESSTRINGCRYPT_ERROR; + } + + /* + * Take note of the final block size + */ + final_block_size = ciphertext[4]; + + /* + * Move pointers and count beyond header + */ + ciphertext += 5; + ciphertext_length -= 5; + + /* + * We will use p to write into the plaintext buffer + */ + p = plaintext; + + /* + * Read the initialization vector + */ + memcpy(IV, ciphertext, 16); + ciphertext += 16; + ciphertext_length -= 16; + + /* + * Hash the IV and password 8192 times + */ + memset(digest, 0, 32); + memcpy(digest, IV, 16); + + for (i = 0; i < 8192; i++) + { + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, digest, 32); + sha256_update(&sha_ctx, + password, + password_length); + sha256_finish(&sha_ctx, + digest); + } + + /* + * Set the AES encryption key + */ + aes_set_key(&aes_ctx, digest, 256); + + /* + * Set the ipad and opad arrays with values as + * per RFC 2104 (HMAC). HMAC is defined as + * H(K XOR opad, H(K XOR ipad, text)) + */ + memset(ipad, 0x36, 64); + memset(opad, 0x5C, 64); + + for (i = 0; i < 32; i++) + { + ipad[i] ^= digest[i]; + opad[i] ^= digest[i]; + } + + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, ipad, 64); + + while (ciphertext_length > 32) + { + memcpy(buffer, ciphertext, 16); + memcpy(buffer2, ciphertext, 16); + ciphertext += 16; + ciphertext_length -= 16; + + sha256_update(&sha_ctx, buffer, 16); + aes_decrypt(&aes_ctx, buffer, buffer); + + /* + * XOR plain text block with previous encrypted output (i.e., use CBC) + */ + for (i = 0; i < 16; i++) + { + buffer[i] ^= IV[i]; + } + + /* + * Update the IV (CBC mode) + */ + memcpy(IV, buffer2, 16); + + /* + * If this is the final block, then we may + * write less than 16 octets + */ + if ((ciphertext_length > 32) || (!final_block_size)) + { + n = 16; + } + else + { + n = final_block_size; + } + + /* + * Write the decrypted block + */ + memcpy(p, buffer, n); + p += n; + } + + /* + * Verify that the HMAC is correct + */ + if (ciphertext_length != 32) + { + return AESSTRINGCRYPT_ERROR; + } + + sha256_finish(&sha_ctx, digest); + sha256_starts(&sha_ctx); + sha256_update(&sha_ctx, opad, 64); + sha256_update(&sha_ctx, digest, 32); + sha256_finish(&sha_ctx, digest); + + if (memcmp(digest, ciphertext, 32)) + { + return AESSTRINGCRYPT_ERROR; + } + + return (p - plaintext); +} + diff --git a/security/AESStringCrypt.h b/security/AESStringCrypt.h new file mode 100755 index 000000000..d2206f688 --- /dev/null +++ b/security/AESStringCrypt.h @@ -0,0 +1,110 @@ +/* + * AESStringCrypt.h + * + * AES String Crypt 1.1 + * Copyright (C) 2007, 2008, 2009, 2012, 2015 + * + * Author: Paul E. Jones + * + * This library will encrypt octet strings of the specified length up + * to ULLONG_MAX - 70 octet in length. If there is an error, the return + * value from the encryption or decryption function will be + * AESSTRINGCRYPT_ERROR. Any other value, including zero, is a valid + * length value. Note that an encrypted string can be up to 69 octets + * longer than the original plaintext string, thus the restriction on the + * input string size. + * + * The output of the string encryption function is a string that is + * compliant with the AES Crypt version 0 file format. For reference, + * see: https://www.aescrypt.com/aes_file_format.html. + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + */ + +#ifndef __STRINGCRYPT_H +#define __STRINGCRYPT_H + +#include + +#include "aes.h" +#include "sha256.h" + +/* + * Define the value to return to indicate an error + */ +#define AESSTRINGCRYPT_ERROR -1 + +typedef unsigned char sha256_t[32]; + +/* + * AESStringCrypt + * + * Description + * This function is called to encrypt the string "plaintext". + * The encrypted string is placed in "ciphertext". Note that + * the encrypted string is up to 68 bytes larger than the + * plaintext string. This is to accomodate the header defined + * by "AES Crypt File Format 0" and to store the last cipher + * block (which is padded to 16 octets). + * + * Parameters + * password [in] + * The password used to encrypt the string in UCS-16 + * format. + * password_length [in] + * The length of the password in octets + * plaintext [in] + * The plaintext string to be encrypted + * plaintext_length [in] + * The length of the plaintext string + * ciphertext [out] + * The encrypted string + * + * Returns + * Returns the length of the ciphertext string or AESSTRINGCRYPT_ERROR + * if there was an error when trying to encrypt the string. + */ +unsigned long long AESStringCrypt( unsigned char *password, + unsigned long password_length, + unsigned char *plaintext, + unsigned long long plaintext_length, + unsigned char *ciphertext); + +/* + * AESStringDecrypt + * + * Description + * This function is called to decrypt the string "ciphertext". + * The decrypted string is placed in "plaintext". + * + * Parameters + * password [in] + * The password used to encrypt the string in UCS-16 + * format. + * password_length [in] + * The length of the password in octets + * ciphertext [in] + * The ciphertext string to be decrypted + * ciphertext_length [in] + * The length of the ciphertext string + * plaintext [out] + * The decrypted string + * + * Returns + * Returns the length of the plaintext string or AESSTRINGCRYPT_ERROR + * if there was an error when trying to encrypt the string. + */ +unsigned long long AESStringDecrypt(unsigned char *password, + unsigned long password_length, + unsigned char *ciphertext, + unsigned long long ciphertext_length, + unsigned char *plaintext); + +#endif /* __STRINGCRYPT_H */ diff --git a/security/Android.mk b/security/Android.mk new file mode 100644 index 000000000..0c4b2bb84 --- /dev/null +++ b/security/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + aes.c \ + AESStringCrypt.c \ + hamlib_passwd.c \ + password.c \ + sha256.c.c + + +LOCAL_MODULE := libsecurity +LOCAL_CFLAGS := +LOCAL_C_INCLUDES := android include +LOCAL_STATIC_LIBRARIES := adat alinco amsat aor ars barrett celestron cnctrk \ + dorji drake dummy easycomm elad ether6 flexradio fodtrack \ + gs232a heathkit icmarine icom ioptron jrc kachina kenwood kit \ + lowe m2 meade pcr prm80 prosistel racal rft \ + rotorez rs sartek satel skanti spid tapr tentec ts7400 tuner \ + uniden wj yaesu radant androidsensor + +LOCAL_LDLIBS := -llog -landroid + +include $(BUILD_SHARED_LIBRARY) diff --git a/security/Makefile.am b/security/Makefile.am new file mode 100644 index 000000000..1c2eb5c34 --- /dev/null +++ b/security/Makefile.am @@ -0,0 +1,13 @@ +EXTRA_DIST = sctest.c +security_test_SOURCES = security_test.c +security_test_LIBS = libsecurity.la +security_test_LDADD = -lhamlib +security_test_LDFLAGS = -L. + +noinst_LTLIBRARIES = libsecurity.la + +libsecurity_la_SOURCES = aes.c AESStringCrypt.c password.c security.c sha256.c +LDADD = $(top_builddir)/src/libhamlib.la +security_test_LDADD = $(LDADD) + +check_PROGRAMS = security_test diff --git a/security/Makefile.nt b/security/Makefile.nt new file mode 100755 index 000000000..8f79c903e --- /dev/null +++ b/security/Makefile.nt @@ -0,0 +1,36 @@ +# +# Makefile for AESStringCrypt test script (Windows) +# Copyright (C) 2007, 2008, 2009, 2012, 2015 +# Paul E. Jones +# +# This software is licensed as "freeware." Permission to distribute +# this software in source and binary forms is hereby granted without a +# fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM THE +# USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, BUT +# NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. +# + +CC = cl.exe + +LINK = link.exe + +RM = del /q + +LIBS = $(conlibs) advapi32.lib + +CFLAGS = -D _CRT_SECURE_NO_WARNINGS /EHsc /O2 /W3 + +OBJS = sctest.obj AESStringCrypt.obj aes.obj sha256.obj + +sctest.exe: $(OBJS) + $(LINK) $(conflags) -out:$@ $(OBJS) $(LIBS) + +%.obj: %.c %.h + $(CC) $(CFLAGS) $(cflags) $(cvars) -c $*.c + +clean: + $(RM) *.obj sctest.exe + diff --git a/security/aes.c b/security/aes.c new file mode 100644 index 000000000..a46bdfdb4 --- /dev/null +++ b/security/aes.c @@ -0,0 +1,886 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2001-2004 Christophe Devine + * + * 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 + */ + +#include "aes.h" + +/* uncomment the following line to run the test suite */ + +/* #define TEST */ + +/* uncomment the following line to use pre-computed tables */ +/* otherwise the tables will be generated at the first run */ + +/* #define FIXED_TABLES */ + +#ifndef FIXED_TABLES + +/* forward S-box & tables */ + +uint32 FSb[256]; +uint32 FT0[256]; +uint32 FT1[256]; +uint32 FT2[256]; +uint32 FT3[256]; + +/* reverse S-box & tables */ + +uint32 RSb[256]; +uint32 RT0[256]; +uint32 RT1[256]; +uint32 RT2[256]; +uint32 RT3[256]; + +/* round constants */ + +uint32 RCON[10]; + +/* tables generation flag */ + +int do_init = 1; + +/* tables generation routine */ + +#define ROTR8(x) ( ( ( x << 24 ) & 0xFFFFFFFF ) | \ + ( ( x & 0xFFFFFFFF ) >> 8 ) ) + +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x] + log[y]) % 255] : 0 ) + +void aes_gen_tables(void) +{ + int i; + uint8 x, y; + uint8 pow[256]; + uint8 log[256]; + + /* compute pow and log tables over GF(2^8) */ + + for (i = 0, x = 1; i < 256; i++, x ^= XTIME(x)) + { + pow[i] = x; + log[x] = i; + } + + /* calculate the round constants */ + + for (i = 0, x = 1; i < 10; i++, x = XTIME(x)) + { + RCON[i] = (uint32) x << 24; + } + + /* generate the forward and reverse S-boxes */ + + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for (i = 1; i < 256; i++) + { + x = pow[255 - log[i]]; + + y = x; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y; y = (y << 1) | (y >> 7); + x ^= y ^ 0x63; + + FSb[i] = x; + RSb[x] = i; + } + + /* generate the forward and reverse tables */ + + for (i = 0; i < 256; i++) + { + x = (unsigned char) FSb[i]; y = XTIME(x); + + FT0[i] = (uint32)(x ^ y) ^ + ((uint32) x << 8) ^ + ((uint32) x << 16) ^ + ((uint32) y << 24); + + FT0[i] &= 0xFFFFFFFF; + + FT1[i] = ROTR8(FT0[i]); + FT2[i] = ROTR8(FT1[i]); + FT3[i] = ROTR8(FT2[i]); + + y = (unsigned char) RSb[i]; + + RT0[i] = ((uint32) MUL(0x0B, y)) ^ + ((uint32) MUL(0x0D, y) << 8) ^ + ((uint32) MUL(0x09, y) << 16) ^ + ((uint32) MUL(0x0E, y) << 24); + + RT0[i] &= 0xFFFFFFFF; + + RT1[i] = ROTR8(RT0[i]); + RT2[i] = ROTR8(RT1[i]); + RT3[i] = ROTR8(RT2[i]); + } +} + +#else + +/* forward S-box */ + +static const uint32 FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* forward tables */ + +#define FT \ +\ + V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ + V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ + V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ + V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ + V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ + V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ + V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ + V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ + V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ + V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ + V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ + V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ + V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ + V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ + V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ + V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ + V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ + V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ + V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ + V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ + V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ + V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ + V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ + V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ + V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ + V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ + V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ + V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ + V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ + V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ + V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ + V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ + V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ + V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ + V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ + V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ + V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ + V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ + V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ + V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ + V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ + V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ + V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ + V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ + V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ + V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ + V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ + V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ + V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ + V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ + V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ + V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ + V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ + V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ + V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ + V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ + V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ + V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ + V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ + V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ + V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ + V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ + V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ + V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32 FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32 FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32 FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32 FT3[256] = { FT }; +#undef V + +#undef FT + +/* reverse S-box */ + +static const uint32 RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* reverse tables */ + +#define RT \ +\ + V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ + V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ + V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ + V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ + V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ + V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ + V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ + V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ + V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ + V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ + V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ + V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ + V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ + V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ + V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ + V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ + V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ + V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ + V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ + V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ + V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ + V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ + V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ + V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ + V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ + V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ + V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ + V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ + V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ + V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ + V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ + V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ + V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ + V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ + V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ + V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ + V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ + V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ + V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ + V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ + V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ + V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ + V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ + V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ + V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ + V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ + V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ + V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ + V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ + V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ + V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ + V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ + V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ + V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ + V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ + V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ + V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ + V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ + V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ + V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ + V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ + V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ + V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ + V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32 RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32 RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32 RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32 RT3[256] = { RT }; +#undef V + +#undef RT + +/* round constants */ + +static const uint32 RCON[10] = +{ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 +}; + +int do_init = 0; + +void aes_gen_tables(void) +{ +} + +#endif + +/* platform-independant 32-bit integer manipulation macros */ + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) ] << 24 ) \ + | ( (uint32) (b)[(i) + 1] << 16 ) \ + | ( (uint32) (b)[(i) + 2] << 8 ) \ + | ( (uint32) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8) ( (n) ); \ +} + +/* decryption key schedule tables */ + +int KT_init = 1; + +uint32 KT0[256]; +uint32 KT1[256]; +uint32 KT2[256]; +uint32 KT3[256]; + +/* AES key scheduling routine */ + +int aes_set_key(aes_context *ctx, uint8 *key, int nbits) +{ + int i; + uint32 *RK, *SK; + + if (do_init) + { + aes_gen_tables(); + + do_init = 0; + } + + switch (nbits) + { + case 128: ctx->nr = 10; break; + + case 192: ctx->nr = 12; break; + + case 256: ctx->nr = 14; break; + + default : return (1); + } + + RK = ctx->erk; + + for (i = 0; i < (nbits >> 5); i++) + { + GET_UINT32(RK[i], key, i * 4); + } + + /* setup encryption round keys */ + + switch (nbits) + { + case 128: + + for (i = 0; i < 10; i++, RK += 4) + { + RK[4] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[3] >> 16) ] << 24) ^ + (FSb[(uint8)(RK[3] >> 8) ] << 16) ^ + (FSb[(uint8)(RK[3]) ] << 8) ^ + (FSb[(uint8)(RK[3] >> 24) ]); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + + break; + + case 192: + + for (i = 0; i < 8; i++, RK += 6) + { + RK[6] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[5] >> 16) ] << 24) ^ + (FSb[(uint8)(RK[5] >> 8) ] << 16) ^ + (FSb[(uint8)(RK[5]) ] << 8) ^ + (FSb[(uint8)(RK[5] >> 24) ]); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + + break; + + case 256: + + for (i = 0; i < 7; i++, RK += 8) + { + RK[8] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[7] >> 16) ] << 24) ^ + (FSb[(uint8)(RK[7] >> 8) ] << 16) ^ + (FSb[(uint8)(RK[7]) ] << 8) ^ + (FSb[(uint8)(RK[7] >> 24) ]); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + (FSb[(uint8)(RK[11] >> 24) ] << 24) ^ + (FSb[(uint8)(RK[11] >> 16) ] << 16) ^ + (FSb[(uint8)(RK[11] >> 8) ] << 8) ^ + (FSb[(uint8)(RK[11]) ]); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + + break; + } + + /* setup decryption round keys */ + + if (KT_init) + { + for (i = 0; i < 256; i++) + { + KT0[i] = RT0[ FSb[i] ]; + KT1[i] = RT1[ FSb[i] ]; + KT2[i] = RT2[ FSb[i] ]; + KT3[i] = RT3[ FSb[i] ]; + } + + KT_init = 0; + } + + SK = ctx->drk; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + for (i = 1; i < ctx->nr; i++) + { + RK -= 8; + + *SK++ = KT0[(uint8)(*RK >> 24) ] ^ + KT1[(uint8)(*RK >> 16) ] ^ + KT2[(uint8)(*RK >> 8) ] ^ + KT3[(uint8)(*RK) ]; RK++; + + *SK++ = KT0[(uint8)(*RK >> 24) ] ^ + KT1[(uint8)(*RK >> 16) ] ^ + KT2[(uint8)(*RK >> 8) ] ^ + KT3[(uint8)(*RK) ]; RK++; + + *SK++ = KT0[(uint8)(*RK >> 24) ] ^ + KT1[(uint8)(*RK >> 16) ] ^ + KT2[(uint8)(*RK >> 8) ] ^ + KT3[(uint8)(*RK) ]; RK++; + + *SK++ = KT0[(uint8)(*RK >> 24) ] ^ + KT1[(uint8)(*RK >> 16) ] ^ + KT2[(uint8)(*RK >> 8) ] ^ + KT3[(uint8)(*RK) ]; RK++; + } + + RK -= 8; + + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + *SK++ = *RK++; + + return (0); +} + +/* AES 128-bit block encryption routine */ + +void aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16]) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->erk; + + GET_UINT32(X0, input, 0); X0 ^= RK[0]; + GET_UINT32(X1, input, 4); X1 ^= RK[1]; + GET_UINT32(X2, input, 8); X2 ^= RK[2]; + GET_UINT32(X3, input, 12); X3 ^= RK[3]; + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y3 ) ]; \ + \ + X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y0 ) ]; \ + \ + X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y1 ) ]; \ + \ + X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + FT3[ (uint8) ( Y2 ) ]; \ +} + + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 1 */ + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 2 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 3 */ + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 4 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 5 */ + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 6 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 7 */ + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 8 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 9 */ + + if (ctx->nr > 10) + { + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 10 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 11 */ + } + + if (ctx->nr > 12) + { + AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 12 */ + AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ (FSb[(uint8)(Y0 >> 24) ] << 24) ^ + (FSb[(uint8)(Y1 >> 16) ] << 16) ^ + (FSb[(uint8)(Y2 >> 8) ] << 8) ^ + (FSb[(uint8)(Y3) ]); + + X1 = RK[1] ^ (FSb[(uint8)(Y1 >> 24) ] << 24) ^ + (FSb[(uint8)(Y2 >> 16) ] << 16) ^ + (FSb[(uint8)(Y3 >> 8) ] << 8) ^ + (FSb[(uint8)(Y0) ]); + + X2 = RK[2] ^ (FSb[(uint8)(Y2 >> 24) ] << 24) ^ + (FSb[(uint8)(Y3 >> 16) ] << 16) ^ + (FSb[(uint8)(Y0 >> 8) ] << 8) ^ + (FSb[(uint8)(Y1) ]); + + X3 = RK[3] ^ (FSb[(uint8)(Y3 >> 24) ] << 24) ^ + (FSb[(uint8)(Y0 >> 16) ] << 16) ^ + (FSb[(uint8)(Y1 >> 8) ] << 8) ^ + (FSb[(uint8)(Y2) ]); + + PUT_UINT32(X0, output, 0); + PUT_UINT32(X1, output, 4); + PUT_UINT32(X2, output, 8); + PUT_UINT32(X3, output, 12); +} + +/* AES 128-bit block decryption routine */ + +void aes_decrypt(aes_context *ctx, uint8 input[16], uint8 output[16]) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->drk; + + GET_UINT32(X0, input, 0); X0 ^= RK[0]; + GET_UINT32(X1, input, 4); X1 ^= RK[1]; + GET_UINT32(X2, input, 8); X2 ^= RK[2]; + GET_UINT32(X3, input, 12); X3 ^= RK[3]; + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + RK += 4; \ + \ + X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y1 ) ]; \ + \ + X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y2 ) ]; \ + \ + X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y3 ) ]; \ + \ + X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ + RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ + RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ + RT3[ (uint8) ( Y0 ) ]; \ +} + + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 1 */ + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 2 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 3 */ + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 4 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 5 */ + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 6 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 7 */ + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 8 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 9 */ + + if (ctx->nr > 10) + { + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 10 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 11 */ + } + + if (ctx->nr > 12) + { + AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 12 */ + AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ (RSb[(uint8)(Y0 >> 24) ] << 24) ^ + (RSb[(uint8)(Y3 >> 16) ] << 16) ^ + (RSb[(uint8)(Y2 >> 8) ] << 8) ^ + (RSb[(uint8)(Y1) ]); + + X1 = RK[1] ^ (RSb[(uint8)(Y1 >> 24) ] << 24) ^ + (RSb[(uint8)(Y0 >> 16) ] << 16) ^ + (RSb[(uint8)(Y3 >> 8) ] << 8) ^ + (RSb[(uint8)(Y2) ]); + + X2 = RK[2] ^ (RSb[(uint8)(Y2 >> 24) ] << 24) ^ + (RSb[(uint8)(Y1 >> 16) ] << 16) ^ + (RSb[(uint8)(Y0 >> 8) ] << 8) ^ + (RSb[(uint8)(Y3) ]); + + X3 = RK[3] ^ (RSb[(uint8)(Y3 >> 24) ] << 24) ^ + (RSb[(uint8)(Y2 >> 16) ] << 16) ^ + (RSb[(uint8)(Y1 >> 8) ] << 8) ^ + (RSb[(uint8)(Y0) ]); + + PUT_UINT32(X0, output, 0); + PUT_UINT32(X1, output, 4); + PUT_UINT32(X2, output, 8); + PUT_UINT32(X3, output, 12); +} + +#ifdef TEST + +#include +#include + +/* + * Rijndael Monte Carlo Test: ECB mode + * source: NIST - rijndael-vals.zip + */ + +static unsigned char AES_enc_test[3][16] = +{ + { + 0xA0, 0x43, 0x77, 0xAB, 0xE2, 0x59, 0xB0, 0xD0, + 0xB5, 0xBA, 0x2D, 0x40, 0xA5, 0x01, 0x97, 0x1B + }, + { + 0x4E, 0x46, 0xF8, 0xC5, 0x09, 0x2B, 0x29, 0xE2, + 0x9A, 0x97, 0x1A, 0x0C, 0xD1, 0xF6, 0x10, 0xFB + }, + { + 0x1F, 0x67, 0x63, 0xDF, 0x80, 0x7A, 0x7E, 0x70, + 0x96, 0x0D, 0x4C, 0xD3, 0x11, 0x8E, 0x60, 0x1A + } +}; + +static unsigned char AES_dec_test[3][16] = +{ + { + 0xF5, 0xBF, 0x8B, 0x37, 0x13, 0x6F, 0x2E, 0x1F, + 0x6B, 0xEC, 0x6F, 0x57, 0x20, 0x21, 0xE3, 0xBA + }, + { + 0xF1, 0xA8, 0x1B, 0x68, 0xF6, 0xE5, 0xA6, 0x27, + 0x1A, 0x8C, 0xB2, 0x4E, 0x7D, 0x94, 0x91, 0xEF + }, + { + 0x4D, 0xE0, 0xC6, 0xDF, 0x7C, 0xB1, 0x69, 0x72, + 0x84, 0x60, 0x4D, 0x60, 0x27, 0x1B, 0xC5, 0x9A + } +}; + +#if 0 +int main(void) +{ + int m, n, i, j; + aes_context ctx; + unsigned char buf[16]; + unsigned char key[32]; + + for (m = 0; m < 2; m++) + { + printf("\n Rijndael Monte Carlo Test (ECB mode) - "); + + if (m == 0) { printf("encryption\n\n"); } + + if (m == 1) { printf("decryption\n\n"); } + + for (n = 0; n < 3; n++) + { + printf(" Test %d, key size = %3d bits: ", + n + 1, 128 + n * 64); + + fflush(stdout); + + memset(buf, 0, 16); + memset(key, 0, 16 + n * 8); + + for (i = 0; i < 400; i++) + { + aes_set_key(&ctx, key, 128 + n * 64); + + for (j = 0; j < 9999; j++) + { + if (m == 0) { aes_encrypt(&ctx, buf, buf); } + + if (m == 1) { aes_decrypt(&ctx, buf, buf); } + } + + if (n > 0) + { + for (j = 0; j < (n << 3); j++) + { + key[j] ^= buf[j + 16 - (n << 3)]; + } + } + + if (m == 0) { aes_encrypt(&ctx, buf, buf); } + + if (m == 1) { aes_decrypt(&ctx, buf, buf); } + + for (j = 0; j < 16; j++) + { + key[j + (n << 3)] ^= buf[j]; + } + } + + if ((m == 0 && memcmp(buf, AES_enc_test[n], 16) != 0) || + (m == 1 && memcmp(buf, AES_dec_test[n], 16) != 0)) + { + printf("failed!\n"); + return (1); + } + + printf("passed.\n"); + } + } + + printf("\n"); + + return (0); +} +#endif +#endif + diff --git a/security/aes.h b/security/aes.h new file mode 100755 index 000000000..7c39f9eed --- /dev/null +++ b/security/aes.h @@ -0,0 +1,24 @@ +#ifndef _AES_H +#define _AES_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +typedef struct +{ + uint32 erk[64]; /* encryption round keys */ + uint32 drk[64]; /* decryption round keys */ + int nr; /* number of rounds */ +} +aes_context; + +int aes_set_key( aes_context *ctx, uint8 *key, int nbits ); +void aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); +void aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); + +#endif /* aes.h */ diff --git a/security/password.c b/security/password.c new file mode 100644 index 000000000..e09f938b7 --- /dev/null +++ b/security/password.c @@ -0,0 +1,85 @@ +/* + * password.c + * + * AESStringCrypt 1.1 + * Copyright (C) 2007, 2008, 2009, 2012, 2015 + * + * Contributors: + * Glenn Washburn + * Paul E. Jones + * Mauro Gilardi + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + */ + +#include +#include +#include +#include +#include "password.h" + +/* + * passwd_to_utf16 + * + * Convert String to UTF-16LE for windows compatibility + */ +int passwd_to_utf16(char *in_passwd, + int length, + int max_length, + char *out_passwd) +{ + char *ic_outbuf, + *ic_inbuf; + iconv_t condesc; + size_t ic_inbytesleft, + ic_outbytesleft; + + ic_inbuf = in_passwd; + ic_inbytesleft = length; + ic_outbytesleft = max_length; + ic_outbuf = out_passwd; + + if ((condesc = iconv_open("UTF-16LE", nl_langinfo(CODESET))) == + (iconv_t)(-1)) + { + perror("Error in iconv_open"); + return -1; + } + + if (iconv(condesc, + &ic_inbuf, + &ic_inbytesleft, + &ic_outbuf, + &ic_outbytesleft) == -1) + { + switch (errno) + { + case E2BIG: + fprintf(stderr, "Error: password too long\n"); + iconv_close(condesc); + return -1; + break; + + default: +#if 0 + printf("EILSEQ(%d), EINVAL(%d), %d\n", EILSEQ, EINVAL, errno); +#endif + fprintf(stderr, + "Error: Invalid or incomplete multibyte sequence\n"); + iconv_close(condesc); + return -1; + } + } + + iconv_close(condesc); + return (max_length - ic_outbytesleft); +} + diff --git a/security/password.h b/security/password.h new file mode 100755 index 000000000..a1025407b --- /dev/null +++ b/security/password.h @@ -0,0 +1,31 @@ +/* + * password.h + * + * AESStringCrypt 1.1 + * Copyright (C) 2007, 2008, 2009, 2012, 2015 + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + */ + +#ifndef __STRINGCRYPT_PASSWORD_H +#define __STRINGCRYPT_PASSWORD_H + +#define MAX_PASSWD_LEN 1024 + +/* + * Function Prototypes + */ +int passwd_to_utf16(char *in_passwd, + int length, + int max_length, + char *out_passwd); + +#endif /* __STRINGCRYPT_PASSWORD_H */ diff --git a/security/sctest.c b/security/sctest.c new file mode 100644 index 000000000..ec37dda63 --- /dev/null +++ b/security/sctest.c @@ -0,0 +1,207 @@ +/* + * String Crypt Test (Linux) + * Copyright (C) 2012, 2015 + * + * Author: Paul E. Jones + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + */ + +#include +#include +#ifdef _WIN32 +#include +//#include +#else +#include +#endif + +#include "AESStringCrypt.h" +#include "password.h" + +/* + * Define how many test vectors to consider + */ +#define TEST_COUNT 21 + +/* + * Dummy string + */ +#define DUMMY_STRING \ + "VOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOID" \ + "VOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOID" \ + "VOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOID" \ + "VOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOIDVOID" + +/* + * Main will just perform some simple test + */ +int main(int argc, char *argv[]) +{ +#ifdef __linux__ + char pass_input[MAX_PASSWD_LEN + 1]; +#endif + char plaintext[512], + ciphertext[512 + 68]; +#ifdef _WIN32 + wchar_t pass[MAX_PASSWD_LEN + 1]; +#else + char pass[MAX_PASSWD_LEN * 2 + 2]; +#endif + int i, + passlen; + unsigned long long plaintext_length, + ciphertext_length; + char *plaintext_tests[TEST_COUNT] = + { + "", + "0", + "012", + "0123456789ABCDE", + "0123456789ABCDEF", + "0123456789ABCDEF0", + "0123456789ABCDEF0123456789ABCDE", + "0123456789ABCDEF0123456789ABCDEF", + "0123456789ABCDEF0123456789ABCDEF0", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDE", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDE", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0" + }; + + /* + * Run through tests + */ + for (i = 0; i < TEST_COUNT; i++) + { + printf("\nStarting test %i\n", i + 1); + + /* + * We will use the password "Hello" + */ +#ifdef _WIN32 + wcscpy(pass, L"Hello"); + passlen = (int) wcslen(pass) * 2; +#else + strcpy(pass_input, "Hello"); + passlen = passwd_to_utf16(pass_input, + strlen(pass_input), + MAX_PASSWD_LEN + 1, + pass); +#endif + + if (passlen <= 0) + { + printf("Error converting the password to UTF-16LE\n"); + return -1; + } + + /* + * Put the text vector into "plaintext" + */ + strcpy(plaintext, pass_input); + printf("Plaintext: %s\n", plaintext); + printf("Plaintext length: %lu\n", strlen(plaintext)); + + /* + * Encrypt the string + */ + printf("Encrypting...\n"); + ciphertext_length = AESStringCrypt((unsigned char *) pass, + passlen, + (unsigned char *) plaintext, + strlen(plaintext), + (unsigned char *) ciphertext); + + if (ciphertext_length == AESSTRINGCRYPT_ERROR) + { + printf("Error encrypting the string\n"); + } + + printf("Ciphertext length: %llu\n", ciphertext_length); + +#if 0 + /* + * One could verify that the data encrypted properly using + * any version of AES Crypt. + */ + { + char file[64]; + FILE *fp; + sprintf(file, "test-%i.txt.aes", i); + fp = fopen(file, "wb"); + fwrite(ciphertext, ciphertext_length, 1, fp); + fclose(fp); + } +#endif + + /* + * Decrypt the ciphertext + */ + strcpy(plaintext, DUMMY_STRING); + printf("Decrypting...\n"); + plaintext_length = AESStringDecrypt((unsigned char *) pass, + passlen, + (unsigned char *) ciphertext, + ciphertext_length, + (unsigned char *) plaintext); + + if (plaintext_length == AESSTRINGCRYPT_ERROR) + { + printf("Error decrypting the string\n"); + } + + printf("Decrypted plaintext length: %llu, %s\n", plaintext_length, plaintext); + + if (plaintext_length != strlen(plaintext_tests[i])) + { + printf("Decrypted length does not match original input length!\n"); + return -1; + } + + /* + * Let's insert a string terminator + */ + plaintext[plaintext_length] = '\0'; + + if (plaintext_length && strcmp(plaintext_tests[i], plaintext)) + { + printf("Decrypted string does not match!\n"); + return -1; + } + + printf("Plaintext matches input: %s\n", plaintext); + } + + printf("\nAll tests passed successfully\n\n"); + + return 0; +} diff --git a/security/security.c b/security/security.c new file mode 100644 index 000000000..cd1d7dbd2 --- /dev/null +++ b/security/security.c @@ -0,0 +1,60 @@ +/* Borrowed for Hamlib from: + * String Crypt Test (Linux) + * Copyright (C) 2012, 2015 + * + * Author: Paul E. Jones + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + */ + +#include +#include +#ifdef _WIN32 +#include +//#include +#else +#include +#endif + +#include "AESStringCrypt.h" +#include "password.h" +#include "../src/misc.h" + +// using tv_usec with a sleep gives a fairly good random number +static int my_rand(int max) +{ + time_t t; + struct timeval tv; + struct tm result; + + t = time(NULL); + gmtime_r(&t, &result); + + gettimeofday(&tv, NULL); + hl_usleep(100); + int val = tv.tv_usec % max; + return val; +} + +void rig_make_key(char key[33]) +{ + char *all = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123467890!@#$%^&*()_=~<>/?"; + int max = strlen(all); + int i; + + for (i = 0; i < 32; ++i) + { + key[i] = all[my_rand(max)]; + } + key[32] = 0; +} + diff --git a/security/security.h b/security/security.h new file mode 100644 index 000000000..e7e4a3973 --- /dev/null +++ b/security/security.h @@ -0,0 +1,2 @@ +int my_rand(int max); +void rig_make_key(char key[33]); diff --git a/security/security_test.c b/security/security_test.c new file mode 100644 index 000000000..0e6d4f9be --- /dev/null +++ b/security/security_test.c @@ -0,0 +1,104 @@ +/* Borrowed for Hamlib from: + * String Crypt Test (Linux) + * Copyright (C) 2012, 2015 + * + * Author: Paul E. Jones + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without a + * fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM + * THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + */ + +#include +#include +#ifdef _WIN32 +#include +//#include +#else +#include +#endif + +#include "AESStringCrypt.h" +#include "password.h" +#include "../src/misc.h" + +// using tv_usec with a sleep gives a fairly good random number +static int my_rand(int max) +{ + time_t t; + struct timeval tv; + struct tm result; + + t = time(NULL); + gmtime_r(&t, &result); + + gettimeofday(&tv, NULL); + hl_usleep(100); + int val = tv.tv_usec % max; + return val; +} + +void rig_make_key(char key[33]) +{ + char *all = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123467890!@#$%^&*()_=~<>/?"; + int max = strlen(all); + int i; + + for (i = 0; i < 32; ++i) + { + key[i] = all[my_rand(max)]; + } + key[32] = 0; +} + +int main() +{ + char key1[33]; + char key2[33]; + char plaintext[33]; + unsigned char ciphertext[1024]; + int ciphertext_length; + int plaintext_length; + memset(ciphertext,0,sizeof(ciphertext)); + rig_make_key(key1); + rig_make_key(key2); + printf("key1=%s\n", key1); + printf("key2=%s\n", key2); + ciphertext_length = AESStringCrypt((unsigned char *) key1, + strlen(key1), + (unsigned char *) key2, + strlen(key2), + (unsigned char *) ciphertext); + + for (int i = 0; i < ciphertext_length; ++i) { printf("%02x", ciphertext[i]); } + + printf("\n"); + + if (ciphertext_length == AESSTRINGCRYPT_ERROR) + { + printf("Error encrypting the string\n"); + } + + printf("Ciphertext length: %d\n", ciphertext_length); + memset(plaintext, 0, sizeof(plaintext)); + printf("Decrypting...\n"); + plaintext_length = AESStringDecrypt((unsigned char *) key1, + strlen(key1), + (unsigned char *) ciphertext, + ciphertext_length, + (unsigned char *) plaintext); + + if (plaintext_length == AESSTRINGCRYPT_ERROR) + { + printf("Error decrypting the string\n"); + } + + printf("Decrypted plaintext length: %d, %s\n", plaintext_length, plaintext); +} diff --git a/security/sha256.c b/security/sha256.c new file mode 100644 index 000000000..7ea3f3ed7 --- /dev/null +++ b/security/sha256.c @@ -0,0 +1,371 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2001-2003 Christophe Devine + * + * 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 + */ + +#include + +#include "sha256.h" + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) ] << 24 ) \ + | ( (uint32) (b)[(i) + 1] << 16 ) \ + | ( (uint32) (b)[(i) + 2] << 8 ) \ + | ( (uint32) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8) ( (n) ); \ +} + +void sha256_starts(sha256_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + 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; +} + +void sha256_process(sha256_context *ctx, uint8 data[64]) +{ + uint32 temp1, temp2, W[64]; + uint32 A, B, C, D, E, F, G, H; + + GET_UINT32(W[0], data, 0); + GET_UINT32(W[1], data, 4); + GET_UINT32(W[2], data, 8); + GET_UINT32(W[3], data, 12); + GET_UINT32(W[4], data, 16); + GET_UINT32(W[5], data, 20); + GET_UINT32(W[6], data, 24); + GET_UINT32(W[7], data, 28); + GET_UINT32(W[8], data, 32); + GET_UINT32(W[9], data, 36); + GET_UINT32(W[10], data, 40); + GET_UINT32(W[11], data, 44); + GET_UINT32(W[12], data, 48); + GET_UINT32(W[13], data, 52); + GET_UINT32(W[14], data, 56); + GET_UINT32(W[15], data, 60); + +#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; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); + P(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); + P(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); + P(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); + P(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); + P(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); + P(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); + P(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); + P(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); + P(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); + P(G, H, A, B, C, D, E, F, W[10], 0x243185BE); + P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); + P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); + P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); + P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); + P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); + P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); + P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); + P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); + P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); + P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); + P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); + P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); + P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA); + P(A, B, C, D, E, F, G, H, R(24), 0x983E5152); + P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D); + P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8); + P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); + P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); + P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147); + P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351); + P(B, C, D, E, F, G, H, A, R(31), 0x14292967); + P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85); + P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); + P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); + P(F, G, H, A, B, C, D, E, R(35), 0x53380D13); + P(E, F, G, H, A, B, C, D, R(36), 0x650A7354); + P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); + P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); + P(B, C, D, E, F, G, H, A, R(39), 0x92722C85); + P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); + P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B); + P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); + P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); + P(E, F, G, H, A, B, C, D, R(44), 0xD192E819); + P(D, E, F, G, H, A, B, C, R(45), 0xD6990624); + P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585); + P(B, C, D, E, F, G, H, A, R(47), 0x106AA070); + P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116); + P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08); + P(G, H, A, B, C, D, E, F, R(50), 0x2748774C); + P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); + P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); + P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); + P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); + P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); + P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE); + P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F); + P(G, H, A, B, C, D, E, F, R(58), 0x84C87814); + P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208); + P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); + P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); + P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); + P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +void sha256_update(sha256_context *ctx, uint8 *input, uint32 length) +{ + uint32 left, fill; + + if (! length) { return; } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += length; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < length) + { + ctx->total[1]++; + } + + if (left && length >= fill) + { + memcpy((void *)(ctx->buffer + left), + (void *) input, fill); + sha256_process(ctx, ctx->buffer); + length -= fill; + input += fill; + left = 0; + } + + while (length >= 64) + { + sha256_process(ctx, input); + length -= 64; + input += 64; + } + + if (length) + { + memcpy((void *)(ctx->buffer + left), + (void *) input, length); + } +} + +static uint8 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 +}; + +void sha256_finish(sha256_context *ctx, uint8 digest[32]) +{ + uint32 last, padn; + uint32 high, low; + uint8 msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32(high, msglen, 0); + PUT_UINT32(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + sha256_update(ctx, sha256_padding, padn); + sha256_update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); + PUT_UINT32(ctx->state[4], digest, 16); + PUT_UINT32(ctx->state[5], digest, 20); + PUT_UINT32(ctx->state[6], digest, 24); + PUT_UINT32(ctx->state[7], digest, 28); +} + +#ifdef TEST + +#include +#include + +/* + * those are the standard FIPS-180-2 test vectors + */ + +static char *msg[] = +{ + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + NULL +}; + +static char *val[] = +{ + "ba7816bf8f01cfea414140de5dae2223" \ + "b00361a396177a9cb410ff61f20015ad", + "248d6a61d20638b8e5c026930c3e6039" \ + "a33ce45964ff2167f6ecedd419db06c1", + "cdc76e5c9914fb9281a1c7e284d73e67" \ + "f1809a48a497200e046d39ccc7112cd0" +}; + +int main(int argc, char *argv[]) +{ + FILE *f; + int i, j; + char output[65]; + sha256_context ctx; + unsigned char buf[1000]; + unsigned char sha256sum[32]; + + if (argc < 2) + { + printf("\n SHA-256 Validation Tests:\n\n"); + + for (i = 0; i < 3; i++) + { + printf(" Test %d ", i + 1); + + sha256_starts(&ctx); + + if (i < 2) + { + sha256_update(&ctx, (uint8 *) msg[i], + strlen(msg[i])); + } + else + { + memset(buf, 'a', 1000); + + for (j = 0; j < 1000; j++) + { + sha256_update(&ctx, (uint8 *) buf, 1000); + } + } + + sha256_finish(&ctx, sha256sum); + + for (j = 0; j < 32; j++) + { + sprintf(output + j * 2, "%02x", sha256sum[j]); + } + + if (memcmp(output, val[i], 64)) + { + printf("failed!\n"); + return (1); + } + + printf("passed.\n"); + } + + printf("\n"); + } + else + { + if (!(f = fopen(argv[1], "rb"))) + { + perror("fopen"); + return (1); + } + + sha256_starts(&ctx); + + while ((i = fread(buf, 1, sizeof(buf), f)) > 0) + { + sha256_update(&ctx, buf, i); + } + + sha256_finish(&ctx, sha256sum); + + for (j = 0; j < 32; j++) + { + printf("%02x", sha256sum[j]); + } + + printf(" %s\n", argv[1]); + } + + return (0); +} + +#endif diff --git a/security/sha256.h b/security/sha256.h new file mode 100755 index 000000000..184a815fa --- /dev/null +++ b/security/sha256.h @@ -0,0 +1,24 @@ +#ifndef _SHA256_H +#define _SHA256_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +typedef struct +{ + uint32 total[2]; + uint32 state[8]; + uint8 buffer[64]; +} +sha256_context; + +void sha256_starts( sha256_context *ctx ); +void sha256_update( sha256_context *ctx, uint8 *input, uint32 length ); +void sha256_finish( sha256_context *ctx, uint8 digest[32] ); + +#endif /* sha256.h */ diff --git a/src/Makefile.am b/src/Makefile.am index b3b4b585a..fe4431de3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,10 +17,10 @@ lib_LTLIBRARIES = libhamlib.la libhamlib_la_SOURCES = $(RIGSRC) libhamlib_la_LDFLAGS = $(WINLDFLAGS) $(OSXLDFLAGS) -no-undefined -version-info $(ABI_VERSION):$(ABI_REVISION):$(ABI_AGE) -libhamlib_la_LIBADD = $(top_builddir)/lib/libmisc.la \ +libhamlib_la_LIBADD = $(top_builddir)/lib/libmisc.la $(top_builddir)/security/libsecurity.la \ $(BACKENDEPS) $(RIG_BACKENDEPS) $(ROT_BACKENDEPS) $(AMP_BACKENDEPS) $(NET_LIBS) $(MATH_LIBS) $(LIBUSB_LIBS) $(INDI_LIBS) -libhamlib_la_DEPENDENCIES = $(top_builddir)/lib/libmisc.la $(BACKENDEPS) $(RIG_BACKENDEPS) $(ROT_BACKENDEPS) $(AMP_BACKENDEPS) +libhamlib_la_DEPENDENCIES = $(top_builddir)/lib/libmisc.la $(top_builddir)/security/libsecurity.la $(BACKENDEPS) $(RIG_BACKENDEPS) $(ROT_BACKENDEPS) $(AMP_BACKENDEPS) EXTRA_DIST = Android.mk hamlibdatetime.h.in diff --git a/src/rig.c b/src/rig.c index 20745be59..d3a586229 100644 --- a/src/rig.c +++ b/src/rig.c @@ -7096,4 +7096,16 @@ void *async_data_handler(void *arg) return NULL; } + +HAMLIB_EXPORT(int) rig_password(RIG *rig, const unsigned char *key1, const unsigned char *key2) +{ + int retval = -RIG_ENIMPL; + ENTERFUNC; + if (rig->caps->password != NULL) + { + retval = rig->caps->password(rig,key1,key2); + } + RETURNFUNC(retval); +} + #endif diff --git a/tests/rigctl.c b/tests/rigctl.c index 1bd14face..e3a2d7673 100644 --- a/tests/rigctl.c +++ b/tests/rigctl.c @@ -648,7 +648,7 @@ int main(int argc, char *argv[]) retcode = rigctl_parse(my_rig, stdin, stdout, argv, argc, NULL, interactive, prompt, &vfo_opt, send_cmd_term, - &ext_resp, &resp_sep); + &ext_resp, &resp_sep, 0); // if we get a hard error we try to reopen the rig again // this should cover short dropouts that can occur diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 1df364cd7..6e2b735b5 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -95,6 +95,10 @@ extern int read_history(); #define ARG_OUT (ARG_OUT1|ARG_OUT2|ARG_OUT3|ARG_OUT4) static int chk_vfo_executed; +char rigctld_password[64]; +int is_passwordOK; +int is_rigctld; + /* variables for readline support */ #ifdef HAVE_LIBREADLINE @@ -349,8 +353,8 @@ static struct test_table test_list[] = { 0xf8, "set_clock", ACTION(set_clock), ARG_IN | ARG_NOVFO, "YYYYMMDDHHMMSS.sss+ZZ" }, { 0xf1, "halt", ACTION(halt), ARG_NOVFO }, /* rigctld only--halt the daemon */ { 0x8c, "pause", ACTION(pause), ARG_IN, "Seconds" }, - { 0x98, "password", ACTION(password), ARG_IN, "Password" }, - { 0x99, "set_password", ACTION(set_password), ARG_IN, "Password" }, + { 0x98, "password", ACTION(password), ARG_IN | ARG_NOVFO, "Password" }, + { 0x99, "set_password", ACTION(set_password), ARG_IN | ARG_NOVFO, "Password" }, { 0xf7, "get_mode_bandwidths", ACTION(get_mode_bandwidths), ARG_IN | ARG_NOVFO, "Mode" }, { 0x00, "", NULL }, }; @@ -643,7 +647,7 @@ static int next_word(char *buffer, int argc, char *argv[], int newline) int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb, int interactive, int prompt, int *vfo_opt, char send_cmd_term, - int *ext_resp_ptr, char *resp_sep_ptr) + int *ext_resp_ptr, char *resp_sep_ptr, int use_password) { int retcode; /* generic return code from functions */ unsigned char cmd; @@ -1684,6 +1688,13 @@ readline_repeat: rig_open(my_rig); } + // chk_vfo is the one command we'll allow without a password + // since it's in the initial handshake + if (use_password && !is_passwordOK && (cmd_entry->arg1 != NULL) && strcmp(cmd_entry->arg1,"ChkVFO")!=0) + { + rig_debug(RIG_DEBUG_ERR, "%s: need password=%s\n", __func__, rigctld_password); + return(-RIG_EPROTO); + } retcode = (*cmd_entry->rig_routine)(my_rig, fout, fin, @@ -2936,7 +2947,9 @@ declare_proto_rig(set_split_vfo) { RETURNFUNC(-RIG_EINVAL); } - rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): rx_vfo = %s, tx_vfo = %s\n", __func__, __LINE__, rig_strvfo(vfo), rig_strvfo(tx_vfo)); + + rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): rx_vfo = %s, tx_vfo = %s\n", __func__, + __LINE__, rig_strvfo(vfo), rig_strvfo(tx_vfo)); RETURNFUNC(rig_set_split_vfo(rig, vfo, (split_t) split, tx_vfo)); } @@ -4662,7 +4675,7 @@ declare_proto_rig(send_cmd) if (backend_num == RIG_KENWOOD || backend_num == RIG_YAESU) { rig_debug(RIG_DEBUG_TRACE, "%s: KENWOOD\n", __func__); - eom_buf[0] = 0; +// eom_buf[0] = 0; send_cmd_term = 0; } @@ -4909,33 +4922,57 @@ declare_proto_rig(pause) return (RIG_OK); } -char rig_passwd[256]; +int rigctld_password_check(RIG *rig, const unsigned char *key1, const unsigned char *key2) +{ + int retval = -RIG_EINVAL; + //fprintf(fout, "password %s\n", password); + rig_debug(RIG_DEBUG_TRACE, "%s: %s == %s\n", __func__, key1, rigctld_password); + is_passwordOK = 0; + if (strcmp((char*)key1, rigctld_password) == 0) + { + retval = RIG_OK; + is_passwordOK = 1; + } + + return(retval); +} + /* 0x98 */ declare_proto_rig(password) { + int retval; const char *passwd = arg1; - if (strcmp(passwd, rig_passwd) == 0) + ENTERFUNC; + if (is_rigctld) + { + retval = rigctld_password_check(rig, (unsigned char*)passwd, NULL); + + if (retval == RIG_OK) { rig_debug(RIG_DEBUG_ERR, "%s: #1 password OK\n", __func__); - return (RIG_EINVAL); + fprintf(fout, "Logged in\n"); } else { - rig_debug(RIG_DEBUG_ERR, "%s: #2 password error, '%s'!='%s'\n", __func__, - passwd, rig_passwd); + rig_debug(RIG_DEBUG_ERR, "%s: password error, '%s'!='%s'\n", __func__, + passwd, rigctld_password); + } + } + else + { + rig_debug(RIG_DEBUG_ERR, "%s: not implemente\n", __func__); } - RETURNFUNC(RIG_OK); + RETURNFUNC(retval); } /* 0x99 */ declare_proto_rig(set_password) { const char *passwd = arg1; - strncpy(rig_passwd, passwd, sizeof(passwd) - 1); - rig_debug(RIG_DEBUG_ERR, "%s: set_password %s\n", __func__, rig_passwd); - fprintf(fout, "set_password %s\n", rig_passwd); + strncpy(rigctld_password, passwd, sizeof(passwd) - 1); + rig_debug(RIG_DEBUG_ERR, "%s: set_password %s\n", __func__, rigctld_password); return (RIG_OK); } diff --git a/tests/rigctl_parse.h b/tests/rigctl_parse.h index e1a86697a..c3351eec6 100644 --- a/tests/rigctl_parse.h +++ b/tests/rigctl_parse.h @@ -51,6 +51,6 @@ int set_conf(RIG *my_rig, char *conf_parms); typedef void (*sync_cb_t)(int); int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb, int interactive, int prompt, int * vfo_mode, char send_cmd_term, - int * ext_resp_ptr, char * resp_sep_ptr); + int * ext_resp_ptr, char * resp_sep_ptr, int use_password); #endif /* RIGCTL_PARSE_H */ diff --git a/tests/rigctld.c b/tests/rigctld.c index a6ae537a5..d7fa01da9 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -84,7 +84,7 @@ * keep up to date SHORT_OPTIONS, usage()'s output and man page. thanks. * TODO: add an option to read from a file */ -#define SHORT_OPTIONS "m:r:p:d:P:D:s:c:T:t:C:W:x:z:lLuovhVZM:n:" +#define SHORT_OPTIONS "m:r:p:d:P:D:s:c:T:t:C:W:w:x:z:lLuovhVZMA:n:" static struct option long_options[] = { {"model", 1, 0, 'm'}, @@ -111,6 +111,7 @@ static struct option long_options[] = {"debug-time-stamps", 0, 0, 'Z'}, {"multicast-addr", 1, 0, 'M'}, {"multicast-port", 1, 0, 'n'}, + {"password", 1, 0, 'A'}, {0, 0, 0, 0} }; @@ -122,6 +123,7 @@ struct handle_data struct sockaddr_storage cli_addr; socklen_t clilen; int vfo_mode; + int use_password; }; @@ -147,6 +149,7 @@ const char *portno = "4532"; const char *src_addr = NULL; /* INADDR_ANY */ const char *multicast_addr = "0.0.0.0"; int multicast_port = 4532; +extern char rigctld_password[64]; #define MAXCONFLEN 1024 @@ -270,6 +273,9 @@ int main(int argc, char *argv[]) struct handle_data *arg; int vfo_mode = 0; /* vfo_mode=0 means target VFO is current VFO */ int i; + extern int is_rigctld; + + is_rigctld = 1; while (1) { @@ -298,6 +304,10 @@ int main(int argc, char *argv[]) printf("rigctl %s\n", hamlib_version2); exit(0); + case 'A': + strncpy(rigctld_password, optarg, sizeof(rigctld_password)-1); + break; + case 'm': if (!optarg) { @@ -947,13 +957,14 @@ int main(int argc, char *argv[]) fd_set set; struct timeval timeout; - arg = malloc(sizeof(struct handle_data)); + arg = calloc(1, sizeof(struct handle_data)); if (!arg) { - rig_debug(RIG_DEBUG_ERR, "malloc: %s\n", strerror(errno)); + rig_debug(RIG_DEBUG_ERR, "calloc: %s\n", strerror(errno)); exit(1); } + if (rigctld_password[0] != 0) arg->use_password = 1; /* use select to allow for periodic checks for CTRL+C */ FD_ZERO(&set); @@ -1172,11 +1183,11 @@ void *handle_socket(void *arg) if (rig_opened) // only do this if rig is open { - rig_debug(RIG_DEBUG_TRACE, "%s: doing rigctl_parse vfo_mode=%d\n", __func__, - handle_data_arg->vfo_mode); + rig_debug(RIG_DEBUG_TRACE, "%s: doing rigctl_parse vfo_mode=%d, secure=%d\n", __func__, + handle_data_arg->vfo_mode, handle_data_arg->use_password); retcode = rigctl_parse(handle_data_arg->rig, fsockin, fsockout, NULL, 0, mutex_rigctld, - 1, 0, &handle_data_arg->vfo_mode, send_cmd_term, &ext_resp, &resp_sep); + 1, 0, &handle_data_arg->vfo_mode, send_cmd_term, &ext_resp, &resp_sep, handle_data_arg->use_password); if (retcode != 0) { rig_debug(RIG_DEBUG_VERBOSE, "%s: rigctl_parse retcode=%d\n", __func__, retcode); } } @@ -1328,6 +1339,7 @@ void usage(void) " -Z, --debug-time-stamps enable time stamps for debug messages\n" " -M, --multicast-addr=addr set multicast UDP address, default 0.0.0.0 (off), recommend 224.0.1.1\n" " -n, --multicast-port=port set multicast UDP port, default 4532\n" + " -A, --password set password for rigctld access\n" " -h, --help display this help and exit\n" " -V, --version output version information and exit\n\n", portno);