LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-08-2012, 04:07 AM   #1
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 703

Rep: Reputation: 111Reputation: 111
shellscript to perform basic encryption


Just as a "fun" project I thought I'd write a script that would encrypt a file and decrypt it as well. The idea is to ask for a password from which a double md5sum is created... Let me give you the code I already have:

Code:
#!/bin/bash

plainfile="unsecret_file.txt"
secretfil="secrets.txt"

ask_password()
{
        echo "Starting ask_password()" >&2
        echo -n "Please provide a password: " >&2
        # naturally, we'd like to obscure this...
        # but that's not the goal at this moment.
        read plainpwd
        echo "${plainpwd}"
}

create_sum()
{
        echo "create_sum()" >&2
        echo $(echo "$@" | md5sum | md5sum | awk '{print $1}')
}

encrypt_file()
{
        echo "encrypt_file()"
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        while read line
        do
                char_counter=0
                newline=""
                while (( char_counter < ${#line} ))
                do
                        newletter=${line:${char_counter}:1}
                        asciival=$(printf "%d" \'${newletter})
                        hashletter=${hash:${hash_counter}:1}
                        hashval=$(printf "%d" \'${hashletter})
                        printf "Letter: %c with ascii value %d\n" ${newletter} ${asciival} >> crypttest.log
                        printf "Hashlt: %c with ascii value %d\n" ${hashletter} ${hashval} >> crypttest.log
                        ((newval=asciival + hashval))
                        printf "Generates a value of %d\n" ${newval} >> crypttest.log
                        newhex=$(printf "%x" ${newval})
                        printf "Value %d is in hex %s (verification %x)\n" ${newval} ${newhex} ${newval} >> crypttest.log
#                       newletter=$(printf "\x%s" ${newhex})
                        newletter=$(printf "\x$(printf "%x" ${newval})")
                        printf "This is letter: %c\n" ${newletter} >> crypttest.log
                        asciival=$(printf "%d" \'${newletter})
                        newhex=$(printf "%x" ${asciival})
                        printf "Squaretest: %c has ascii val %d which is %s in hex\n" ${newletter} ${asciival} ${newhex} >> crypttest.log
                        newline=$(printf "%s%c" ${newline} ${newletter})
                        ((hash_counter++))
                        ((char_counter++))
                        if (( hash_counter > ${#hash} ))
                        then
                                hash_counter=0
                        fi
                done
                echo ${newline} >> ${secretfil}
        done < ${plainfile}
}

decrypt_file()
{
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        while read line
        do
                char_counter=0
                newline=""
                while ((char_counter < ${#line}))
                do
                        newletter=${line:${char_counter}:1}
                        asciival=$(printf "%d" \'${newletter})
                        hashletter=${hash:${hash_counter}:1}
                        hashval=$(printf "%d" \'${hashletter})
                        printf "Letter: %c with ascii value %d\n" ${newletter} ${asciival} >> decrypt.log
                        printf "Hashlt: %c with ascii value %d\n" ${hashletter} ${hashval} >> decrypt.log
                        ((newval=asciival - hashval))
                        printf "Generates a value of %d\n" ${newval} >> decrypt.log
                        newletetr=$(printf "\x$(printf %x ${newval})")
                        newline=$(printf "%s%c" ${newline} ${newletter})
                        ((hash_counter++))
                        ((char_counter++))
                        if ((hash_counter > ${#hash} ))
                        then
                                hash_counter=0
                        fi
                done
                echo "${newline}" >> testje.txt
        done < ${secretfil}
}

main()
{
        echo "Starting main..."
        encrypt_file
        decrypt_file
}

main
Right now, I'm not too interested in decrypt_file(); there's something odd in the encrypt_file() function.

Simply put, the function takes a character from the line in the file, as well as a character from the hash string. Calculates both ascii values and adds them; this value is converted to hex, to write a new character.
When I check the logging I put in, I notice something odd:
a hex-value that I calculated is for example "d5", but when I create a character from that, and then calculate it's hex-value back (square testing) I notice that the value has become "fffffffd5"; Where did this switch (signedness I gather) occur? I don't really see that.

Hope someone with a bright eye sees where I went wrong.

Last edited by Ramurd; 02-08-2012 at 04:08 AM.
 
Old 02-08-2012, 06:06 AM   #2
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 703

Original Poster
Rep: Reputation: 111Reputation: 111
An excerpt from the logging (crypttest.log) that I generated looks like this:

Quote:
Letter: u with ascii value 117
Hashlt: e with ascii value 101
Generates a value of 218
Value 218 is in hex da (verification da)
This is letter: Ã
Squaretest: Ã has ascii val -38 which is ffffffffffffffda in hex
you can see that all leading zeroes in hex have become f, but it's not a simple inversion that happened here; otherwise the last two bytes (da) would have been affected as well. When the values went above 255 I would somewhat understand this, but that appears to be not the case here... it happens all the time.

hmm... 255 would be extended ascii (I guess); might be 128 is the max and causes the sign-flip?

Edit:
That appears to be possible:
Quote:
Letter: 0 with ascii value 0
Hashlt: t with ascii value 116
Generates a value of 116
Value 116 is in hex 74 (verification 74)
This is letter: t
Squaretest: t has ascii val 116 which is 74 in hex

Last edited by Ramurd; 02-08-2012 at 06:09 AM.
 
Old 02-08-2012, 06:28 AM   #3
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 703

Original Poster
Rep: Reputation: 111Reputation: 111
Getting closer; but not entirely 'there' yet:

Code:
#!/bin/bash

plainfile="unsecret_file.txt"
secretfil="secrets.txt"

ask_password()
{
        echo "Starting ask_password()" >&2
        echo -n "Please provide a password: " >&2
        # naturally, we'd like to obscure this...
        # but that's not the goal at this moment.
        read plainpwd
        echo "${plainpwd}"
}

create_sum()
{
        echo "create_sum()" >&2
        echo $(echo "$@" | md5sum | md5sum | awk '{print $1}')
}

encrypt_file()
{
        echo "encrypt_file()"
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        while read line
        do
         char_counter=0
         newline=""
         while (( char_counter < ${#line} ))
         do
                newletter=${line:${char_counter}:1}
                asciival=$(printf "%d" \'${newletter})
                hashletter=${hash:${hash_counter}:1}
                hashval=$(printf "%d" \'${hashletter})
                printf "Letter: %c with ascii value %d\n" ${newletter} ${asciival} >> crypttest.log
                printf "Hashlt: %c with ascii value %d\n" ${hashletter} ${hashval} >> crypttest.log
                ((newval=asciival + hashval))
                if (( newval > 128 ))
                then
                        ((newval-=128))
                fi
                printf "Generates a value of %d\n" ${newval} >> crypttest.log
                newhex=$(printf "%x" ${newval})
                printf "Value %d is in hex %s (verification %x)\n" ${newval} ${newhex} ${newval} >> crypttest.log
#               newletter=$(printf "\x%s" ${newhex})
                newletter=$(printf "\x$(printf "%x" ${newval})")
                printf "This is letter: %c\n" ${newletter} >> crypttest.log
                asciival=$(printf "%d" \'${newletter})
                newhex=$(printf "%x" ${asciival})
                printf "Squaretest: %c has ascii val %d which is %s in hex\n" ${newletter} ${asciival} ${newhex} >> crypttest.log
                newline=$(printf "%s%c" ${newline} ${newletter})
                ((hash_counter++))
                ((char_counter++))
                if (( hash_counter > ${#hash} ))
                then
                        hash_counter=0
                fi
         done
         echo ${newline} >> ${secretfil}
        done < ${plainfile}
}

decrypt_file()
{
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        while read line
        do
         char_counter=0
         newline=""
         while ((char_counter < ${#line}))
         do
                newletter=${line:${char_counter}:1}
                asciival=$(printf "%d" \'${newletter})
                hashletter=${hash:${hash_counter}:1}
                hashval=$(printf "%d" \'${hashletter})
                printf "Letter: %c with ascii value %d\n" ${newletter} ${asciival} >> decrypt.log
                printf "Hashlt: %c with ascii value %d\n" ${hashletter} ${hashval} >> decrypt.log
                ((newval=asciival - hashval))
                if ((newval < 0))
                then
                        ((newval+=128))
                fi
                printf "Generates a value of %d\n" ${newval} >> decrypt.log
                newletter=$(printf "\x$(printf %x ${newval})")
                printf "This is letter %c\n" ${newletter} >> decrypt.log
                newline=$(printf "%s%c" ${newline} ${newletter})
                ((hash_counter++))
                ((char_counter++))
                if ((hash_counter > ${#hash} ))
                then
                        hash_counter=0
                fi
         done
         echo "${newline}" >> testje.txt
        done < ${secretfil}
}

main()
{
        echo "Starting main..."
        encrypt_file
        decrypt_file
}

main
 
Old 02-08-2012, 06:56 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Since you're using Bash, you can use
Code:
typeset +x plainpwd
read -p 'Password: ' -s plainpwd
The typeset +x means that plainpwd should not be automatically exported as an environment variable. If you are careful to keep plainpwd as Bash variable, never export it to the environment, and never use it as a command line parameter to a non-builtin command, the password can be considered relatively safe.

(In particular, processes belonging to the same user can still sniff the password by reading /proc/pid/mem, the memory belonging to the Bash process. But it is not directly and easily accessible.)

Character codes 32..126 are ASCII printable letters. Codes 0..31 and 127 are control characters. Since on all Linux architectures bytes are eight bits wide, but the signedness of the non-ASCII characters varies, you should just AND with the 8-bit mask (code & 255) to make sure the non-ASCII characters occupy codes 128..255; this is the standard convention. The interpretation of codes 128..255 == -128..-1 depend on the character set used. In particular, when using UTF-8, many characters consist of multiple bytes in that range.

A nifty way to convert the password -- or indeed any other string -- to an array of prefixless hex numbers is via od:
Code:
export LC_ALL=C LANG=C
hex=($(builtin echo -n "$plainpwd" | od --width=${#plainpwd} -t x1 | sed -ne '1 s|^[0-9A-Fa-f]* ||p'))
Or, to a big-endian hexadecimal number,
Code:
export LC_ALL=C LANG=C
hex=$(builtin echo -n "$plainpwd" | od --width=${#plainpwd} -t x1 | sed -ne '1 s|^[0-9A-Fa-f]*||p' | tr -cd '0-9A-Fa-f')
You do need to set LC_ALL and LANG to C, because in UTF-8 locales the byte count of a string and the character count of a string do not match. For example, in UTF-8, € = e2 82 ac, i.e. three bytes, but one character. If you really don't want to do that, you can use --width=$[4*${#plainpwd}] instead; this makes sure that od outputs all the hex bytes on a single line. (Currently an UTF-8 character may need up to four bytes, although full UCS support requires up to six bytes per character.)

The builtin keyword makes sure the echo is done by the Bash shell itself, and that it will never execute an external program with the plain password as its parameter. This ensures the plain password is never used directly as a command-line argument, and is thus not leaked to the process list.

As you probably know, all command arguments are visible in the process list, e.g. via ps -e -o pid,comm,args

Edited to add:

Please also consider salting your hashes. Instead of just doing (mathematically)
Code:
result = hash(plaintext)
do
Code:
salt = random number or string, typically 8 - 16 characters
result = salt + optional_separator_1 + hash(salt + optional_separator_2 + plaintext)
The result of this salting is that you can no longer generate a large dictionary of hashes of candidate passwords, and just compare to your hash. Each different salt would need a new dictionary!

For example:
Code:
salt=$(dd if=/dev/urandom bs=16 count=1 of=/dev/stdout 2>/dev/null | od --width=16 -t x1 | sed -ne '1 s|^[^ ]* ||p' | tr -cd '0-9A-Fa-f')
secret="this is the secret text"
hash=$(echo -n "$salt|$secret" | sha256sum -b | sed -ne '1 s| .*$||p')
result="$salt|$hash"
echo "Result: $result"
produces a different hash every time. To check if a response matches the secret, use
Code:
read -p 'Response: ' -s response
salt="${result%%|*}"
hash=$(echo -n "$salt|$response" | sha256sum -b | sed -ne '1 s| .*$||p')
[ "$result" = "$salt|$hash" ] && echo "Matches" || echo "Does not match"

Last edited by Nominal Animal; 02-08-2012 at 07:11 AM.
 
1 members found this post helpful.
Old 02-08-2012, 08:09 AM   #5
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 703

Original Poster
Rep: Reputation: 111Reputation: 111
well, this script could use indeed some optimizations; Strength of hashes and the rest of the security being a few.
My main mistake was in ascii table being only 0-127; once altered the decryption of the encrypted file results in the original file, which pretty much was the goal.

The next thing is ironing some flaws out; but the main reason to start this little project is that I have a configuration file for a script that contains plain-text passwords. I wanted to obscure those in such a way, that they are not readily readable; There are a few more things that I'll have to think about, once I get there...

The thing that is happening right now is:
script reads configfile and "generates" an ssh-command: ssh <user>@<host> "<command with plain text passwords>"; those commands would've been entered on a commandline otherwise (and thus also readily readable).

Those passwords will be readily readable on the target host process list anyway; where I have little room at all to hide them from the process list. Thinking some stuff up though, while we're at it.

Right now, the script looks like this:
Code:
#!/bin/bash

plainfile="unsecret_file.txt"
secretfil="secrets.txt"

ask_password()
{
        echo "Starting ask_password()" >&2
        echo -n "Please provide a password: " >&2
        # naturally, we'd like to obscure this...
        # but that's not the goal at this moment.
        read plainpwd
        echo "${plainpwd}"
}

create_sum()
{
        echo "create_sum()" >&2
        echo $(echo "$@" | md5sum | md5sum | awk '{print $1}')
}

encrypt_file()
{
        echo "encrypt_file()"
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        printf "hash: %s\n" ${hash} >> crypttest.log
        while read line
        do
                char_counter=0
                newline=""
                printf "|----- Processing line: %s\n" "${line}" >> crypttest.log
                printf "|----- Hash counter: %d\n" ${hash_counter} >> crypttest.log
                while (( char_counter < ${#line} ))
                do
                        newletter=${line:${char_counter}:1}
                        asciival=$(printf "%d" \'"${newletter}")
                        hashletter=${hash:${hash_counter}:1}
                        hashval=$(printf "%d" \'"${hashletter}")
                        printf "Letter: \"%c\" with ascii value %d\n" "${newletter}" ${asciival} >> crypttest.log
                        printf "Hashlt: %c with ascii value %d\n" "${hashletter}" ${hashval} >> crypttest.log
                        ((newval=asciival + hashval))
                        if (( newval > 126 ))
                        then
                                ((newval-=126))
                        fi
                        printf "Generates a value of %d\n" ${newval} >> crypttest.log
                        newhex=$(printf "%x" ${newval})
                        printf "Value %d is in hex %s (verification %x)\n" ${newval} ${newhex} ${newval} >> crypttest.log
                        newletter=$(printf "\x$(printf "%x" ${newval})")
                        printf "This is letter: \"%c\"\n" "${newletter}" >> crypttest.log
                        asciival=$(printf "%d" \'"${newletter}")
                        newhex=$(printf "%x" ${asciival})
                        printf "Squaretest: %c has ascii val %d which is %s in hex\n" "${newletter}" ${asciival} ${newhex} >> crypttest.log 2>&1
                        newline=$(printf "%s%c" "${newline}" "${newletter}")
                        ((hash_counter++))
                        ((char_counter++))
                        if (( hash_counter > ${#hash} ))
                        then
                                printf "|----- Reset hash_counter (%d)\n" ${hash_counter} >> crypttest.log
                                hash_counter=0
                        fi
                done
                echo ${newline} >> ${secretfil}
        done < ${plainfile}
}

decrypt_file()
{
        plainpwd=$(ask_password)
        hash=$(create_sum "${plainpwd}")

        hash_counter=0
        while read line
        do
                char_counter=0
                newline=""
                printf "|----- Processing line: %s\n" "${line}" >> decrypt.log
                printf "|----- Hash counter: %d\n" ${hash_counter} >> decrypt.log
                while ((char_counter < ${#line}))
                do
                        newletter=${line:${char_counter}:1}
                        asciival=$(printf "%d" \'"${newletter}")
                        hashletter=${hash:${hash_counter}:1}
                        hashval=$(printf "%d" \'"${hashletter}")
                        printf "Letter: %c with ascii value %d\n" "${newletter}" ${asciival} >> decrypt.log 2>&1
                        printf "Hashlt: %c with ascii value %d\n" "${hashletter}" ${hashval} >> decrypt.log 2>&1
                        ((newval=asciival - hashval))
                        if ((newval < 0))
                        then
                                ((newval+=126))
                        fi
                        printf "Generates a value of %d\n" ${newval} >> decrypt.log
                        newletter=$(printf "\x$(printf %x ${newval})")
                        printf "This is letter "%c"\n" "${newletter}" >> decrypt.log
                        newline=$(printf "%s%c" "${newline}" "${newletter}")
                        ((hash_counter++))
                        ((char_counter++))
                        if (( hash_counter > ${#hash} ))
                        then
                                printf "|----- Reset hash counter (%d)\n" ${hash_counter} >> decrypt.log
                                hash_counter=0
                        fi
                done
                echo "${newline}" >> testje.txt
        done < ${secretfil}
}

main()
{
        echo "Starting main..."
        rm -vf crypttest.log
        rm -vf decrypt.log
        rm -vf testje.txt
        rm -vf ${secretfil}
        encrypt_file
        decrypt_file
}

main
Edit: nvm; this does not work yet; parts remain garbled after decryption...

Last edited by Ramurd; 02-08-2012 at 08:16 AM.
 
Old 02-08-2012, 08:19 AM   #6
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
How efficient is this script ? I'm just wondering.
 
Old 02-08-2012, 08:22 AM   #7
Ramurd
Member
 
Registered: Mar 2009
Location: Rotterdam, the Netherlands
Distribution: Slackwarelinux
Posts: 703

Original Poster
Rep: Reputation: 111Reputation: 111
Quote:
Originally Posted by H_TeXMeX_H View Post
How efficient is this script ? I'm just wondering.
not at all
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Linux password encryption and data encryption Tux-Slack Programming 4 06-20-2007 06:46 AM
how to update the encryption from basic to md5[apache] edenCC Linux - Software 0 01-28-2007 09:22 PM
Which CDs do I need to perform a basic installation? Deelk Fedora 1 06-04-2006 05:02 AM
how to perform basic instalation and how to use kopete alex_zcb Linux - General 0 11-28-2004 04:54 PM
Mandrake 9.0 Wireless Works without encryption.. does not with encryption topcat Linux - Wireless Networking 3 05-04-2003 08:47 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:04 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration