diff options
-rw-r--r-- | hashpwd.cpp | 278 | ||||
-rw-r--r-- | src/Makefile.am | 27 | ||||
-rwxr-xr-x | ubpasswd.sh | 108 |
3 files changed, 409 insertions, 4 deletions
diff --git a/hashpwd.cpp b/hashpwd.cpp new file mode 100644 index 0000000..79f0667 --- /dev/null +++ b/hashpwd.cpp @@ -0,0 +1,278 @@ +//============================================================================ +// Name : hashpwd.cpp +// Author : +// Version : +// Copyright : Your copyright notice +// Description : Hello World in C++, Ansi-style +//============================================================================ + +#include <iostream> +#include <sstream> +#include <string> +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <iomanip> +#include <string.h> +#include <openssl/sha.h> + +using namespace std; +int v = 0; + +string magic_comp = "fc1c"; + +static const string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +void escapeOutput(string &input, string &outstr) +{ + outstr.clear(); + int idx = 0; int lastnl = 0; + for (string::iterator it=input.begin(); it!=input.end(); ++it) { + stringstream conv; + lastnl = 0; + if (isprint(*it)) { + if (idx > 0) { + outstr += ' '; + idx++; + } + outstr += *it; + idx++; + if(idx > 74) { + outstr += '\n'; + lastnl = 1; + } + } else { + conv.str(string()); + conv << "\\x" << hex << setw(2) << ((unsigned int)*it & 0xff); + if (idx > 0) { + outstr += ' '; + idx++; + } + idx+=5; + outstr += conv.str(); + if(idx > 74) { + outstr += '\n'; + lastnl = 1; + } + } + } + if(lastnl) + if (outstr.size () > 0) outstr.resize (outstr.size () - 1); +} + +void binTo64(const unsigned char *data, unsigned int datalen, string &str, unsigned int strLen) +{ + unsigned int idx = 0; + int sex; + unsigned char incoming[3]; + int last; + + str.clear(); + (v == 1) && cout << "binTo64 datalen: " << datalen << endl; + (v == 1) && cout << "binTo64 strLen: " << strLen << endl; + for(unsigned int i=0; i<strLen; i+=4) { + if(idx >= datalen) + break; + if (idx + 3 > datalen) { + memset(incoming,0,3); + memcpy(incoming,data+idx,datalen-idx); + last = datalen - idx - 1; + } else { + memcpy(incoming,data+idx,sizeof incoming); + last = 4; + } + idx += 3; + + (v == 1) && cout << hex << "in[0]: " << (int)incoming[0] << " in[1]: " << (int)incoming[1]<< " in[2] " << (int)incoming[2] << endl; + + sex = (incoming[0] >> 2); + str += base64_chars[sex]; + (v == 1) && cout << "1st, 4th inp char: " << hex << sex << " to: " << str << endl; + + sex = (incoming[1] >> 4); + (v == 1) && cout << "2nd, 5th inp char: " << hex << sex << endl; + sex += (incoming[0] << 4) & 0x30; + str += base64_chars[sex]; + (v == 1) && cout << "3rd, 6th inp char: " << hex << sex << " to: " << str << endl; + (v == 1) && cout << "last: " << last << endl; + if (last == 0) + continue; + sex = (incoming[2] >> 6); + sex += ((incoming[1] << 2) & 0x3c); + str += base64_chars[sex]; + + if(last == 1) + continue; + + sex = (incoming[2] & 0x3f); + str += base64_chars[sex]; + + (v == 1) && cout << "Converted " << idx << "chars: " << str << endl; + } + while (str.length() < strLen) + str += '='; + return; +} + +int badPassword(string &passwd) +{ + unsigned char a[3]; + int i = 0; + int lower=0, upper=0, numeric=0, special=0; + a[0] = a[1] = a[2] = 0; + for (string::iterator it=passwd.begin(); it!=passwd.end(); ++it) { + a[0] = *it; + if (i > 1) { + if ((a[0] == a[1]) && (a[1] == a[2])) + return 1; + if ((a[0] == a[1]+1) && (a[1] == a[2]+1)) + return 1; + if ((a[0] == a[1]-1) && (a[1] == a[2]-1)) + return 1; + } + a[2] = a[1]; + a[1] = a[0]; + if(islower(*it)) + lower=1; + if(isupper(*it)) + upper=1; + if(isdigit(*it)) + numeric=1; + if((*it == '/') || (*it == '+')) + special=1; + i++; + } + if (lower + upper + numeric + special < 3) + return 1; + return 0; +} + +void usage(void) +{ + cout << "usage:" << endl << + " mts-hashpwd [-v] [[-d did] [-m mac] | [-p password]] salt" << endl << + " -v verbose" << endl << + " -d did Device ID (serial #)" << endl << + " -m mac Ethernet mac address" << endl << + " -p password" << endl << + "Either password must be supplied, or Device-ID and Ethernet Mac address" << endl << + "salt is required." <<endl; + exit(1); +} + +int main(int argc, char **argv) { + int opt = 0, p = 0, d = 0, m = 0; + unsigned long long fudge = 0; + short unsigned int prefix; + string did, mac, pwd, salt; + + while ((opt = getopt(argc,argv,"d:m:p:v")) != EOF) + switch(opt) + { + case 'v': v = 1; cout << " verbose" <<endl; break; + case 'd': d = 1; did = optarg ; (v==1) && cout << "device-id is " << did << endl; break; + case 'm': m = 1; mac = optarg ; (v==1) && cout << "Ethernet mac is " << mac << endl; break; + case 'p': p = 1; pwd = optarg ; (v==1) && cout << "User defined password is \"" << pwd << "\"" << endl; break; + case '?': usage(); break; + default: cout<<endl; abort(); + } + (v == 1) && cout << "optind is " << optind << " and argc is " << argc << endl; + if (v == 1) { + cout << "arguments:" << endl; + for (int i = 0; i < argc; i++) + cout << " argv[" << i << "]=\"" << argv[i] << "\"" << endl; + } + + if ((p && d) || (p && m)) { + cout << "Must use either a supplied password or Device ID and Ethernet MAC address, but not all three." << endl; + usage(); + } + if ((d && !m) || (m && !d)) { + cout << "Must have both a Device-ID and an Ethernet MAC address." << endl; + usage(); + } + if (optind != argc-1) { + cout << "Must have exactly one salt argument." << endl; + usage(); + } + salt = argv[optind]; + (v == 1) && cout << "Salt is \"" << salt << "\"" << endl; + + prefix = strtol(magic_comp.c_str(),NULL,16); + + prefix = ~prefix; + + stringstream prefixStream; + + prefixStream << setw(4) << setfill('0') << hex << prefix; + + (v == 1) && cout << "prefix is " << prefixStream.str() << endl; + + + string passwd_str; + string passwd0, passwdnew; + SHA256_CTX sha256; + unsigned char hash[SHA256_DIGEST_LENGTH]; + + if(!p) { + passwd0 = did + "|" + mac; + passwdnew = passwd0; + + while (1) { + unsigned char append[9]; + (v == 1) && cout << "pwdinput: " << passwdnew << endl; + + SHA256_Init(&sha256); + SHA256_Update(&sha256,passwdnew.c_str(),passwdnew.length()); + SHA256_Final(hash, &sha256); + if (v == 1) { + for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) + cout << hex << setw(2) << setfill('0') << (int)hash[i]; + cout << endl; + } + pwd = ""; + binTo64(hash,SHA256_DIGEST_LENGTH,pwd,8); + (v == 1) && cout << "passwd_str: " << pwd << endl; + if(!badPassword(pwd)) + break; + fudge++; + memcpy(append,&fudge,sizeof fudge); + append[8]=0; + string b64Appendstr; + binTo64(append,8,b64Appendstr,12); + unsigned int found = b64Appendstr.find_first_of('='); + if(found != string::npos) + b64Appendstr = b64Appendstr.substr(0,found); + passwdnew = passwd0 + b64Appendstr; + } +#ifdef Runtest + // Test + string testencode = "aX2t^%~Q\377\377\xef", outencode, escaped ; + escapeOutput(testencode,escaped); + binTo64((unsigned char *)testencode.c_str(),testencode.length(),outencode,testencode.length()*2); + cout << "TEST encode input: " << escaped << " Output: " << + outencode << endl; +#endif + } + + cout << "pass=" << pwd << endl; + + passwd_str = prefixStream.str() + pwd + salt; + + SHA256_Init(&sha256); + SHA256_Update(&sha256,passwd_str.c_str(),passwd_str.length()); + SHA256_Final(hash, &sha256); + + cout << "password_hash="; + cout << hex; + for (int i=0; i < SHA256_DIGEST_LENGTH; i++) + cout << setw(2) << setfill('0') << (int)hash[i]; + cout << endl; + cout << "salt=" << salt << endl; + return 0; +} diff --git a/src/Makefile.am b/src/Makefile.am index bfeafff..12f084c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,12 +1,31 @@ +## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = gnu AM_CFLAGS = -Wall -bin_PROGRAMS = mts-id-eeprom hashpwd +bin_PROGRAMS = mts-id-eeprom +sbin_PROGRAMS = mts-hashpwd +mts_hashpwd_SOURCES = hashpwd.cpp mts_id_eeprom_SOURCES = eeprom_main.c -hashpwd_SOURCES = hashpwd.cpp noinst_HEADERS = eeprom.h -hashpwd_LDADD = -lcrypto - +mts_hashpwd_LDADD = -lcrypto +sbin_SCRIPTS = ubpasswd.sh EXTRA_DIST = +SUFFIXES = .sh + +.sh: + $(shbin_verbose) cp $< $@.tmp + $(AM_V_at) chmod 0744 $@.tmp + $(AM_V_at) mv -f $@.tmp $@ + +# Since this is Yocto we just make it work by moving +# the sbin stuff to /sbin, and set permissions +# on the script for root. +install-exec-hook: + cd $(DESTDIR)$(sbindir) && mkdir ../../sbin && \ + mv ubpasswd.sh ../../sbin/mts-ubpasswd && \ + chmod 0744 ../../sbin/mts-ubpasswd + cd $(DESTDIR)$(sbindir) && \ + mv mts-hashpwd ../../sbin/mts-hashpwd + rmdir $(DESTDIR)$(sbindir) diff --git a/ubpasswd.sh b/ubpasswd.sh new file mode 100755 index 0000000..000c831 --- /dev/null +++ b/ubpasswd.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# Password setting/generation script. +# Sets both root and u-boot password, +# or optionally just U-boot. +# What is actually written is the password +# and salt. But the password is printed +# for reference. +# ubpasswd -h will print usage. +if ! [[ -x /sbin/hashpwd ]] ; then + echo Need /sbin/hashpwd to proceed. +fi +usage() { + echo "ubpasswd [-u] [-d] [-s salt] [password]" + echo " -u means u-boot only (not UNIX password)" + echo " -s salt is user supplied salt" + echo " -d debug" + echo " password is a user supplied password" + echo "A salt not supplied is generated." + echo "If a password is not supplied, it is generated" + exit 1 +} +((ubonly=0)) +((hassalt=0)) +((debug=0)) +((upwd=0)) +while getopts ":dus:" opt; do + case $opt in + u) + ((ubonly=1)) + ;; + s) + salt="$OPTARG" + ((hassalt=1)) + ;; + d) + ((debug=1)) + ;; + *) + usage + esac +done +((debug)) && echo OPTIND is $OPTIND +((sc=OPTIND-1)) +shift $sc +if (($# == 1)) ; then + ((debug)) && echo "User set password is \"$1\"" + ((upwd = 1)) + pass="$1" +fi + +((debug)) && echo hassalt is $hassalt, salt is \"$salt\" +((debug)) && echo ubonly is $ubonly +((debug)) && echo debug is $debug + +len=8 +saltlen=128 +mts=/sys/devices/platform/mts-io +did="${mts}/device-id" +mac="${mts}/mac-eth" + +if ! /bin/fgrep "mts password protected" /dev/mtdblock2 >/dev/null 2>&1; then + echo "U-Boot does not support password protection." +fi + +if ((hassalt == 0)) ; then + salt="$(/bin/dd if=/dev/urandom count=1 bs=128 2>/dev/null | /bin/base64 | tr -d '\n' | cut -c1-${saltlen})" +fi + +echo "salt: $salt" + +((v == 1)) && echo upwd is $upwd +((v == 1)) && echo did length is ${#did} +if ((upwd == 0)) ; then + if ((${#did} == 0)) ; then + echo "${mts}/device-id must have a non-zero length value" + usage + fi + if ((${#mac} == 0)) ; then + echo "${mts}/mac-eth must have a non-zero length value" + usage + fi + if ((v == 1)) ; then + echo Try this: + echo "/sbin/hashpwd -d ${did} -m ${mac} ${salt}" + fi + result=$(/sbin/hashpwd -d ${did} -m ${mac} ${salt}) +else + result=$(/sbin/hashpwd -p "${pass}" ${salt}) +fi +if ! [[ $result =~ ^pass=([^[:space:]]+)[[:space:]]+password_hash=([^[:space:]]+) ]] ; then + echo "/sbin/hashpwd failed: ${result}" + exit 1 +fi +if ((v == 1)) ; then + echo result is: + echo "$result" +fi +pass="${BASH_REMATCH[1]}" +password_hash="${BASH_REMATCH[2]}" +echo "uboot password hash: \"$password_hash\"" +if ((ubonly == 0)) ; then + echo "setting root password to ${pass}" + echo -e "${pass}\n${pass}" | /usr/bin/passwd >/dev/null 2>&1 +fi +set -e +echo "u-boot password is ${pass}" +/usr/bin/u-boot setenv mtss "$salt" +/usr/bin/u-boot setenv mtsp "$password_hash" |