Version 18 of Secure expect

Updated 2004-01-17 12:43:04

RJ Bacon (I work in a NOC - this was a BIG problem for us) suggests an approach to avoiding embedded passwords in Expect scripts. Feel free to format this for wiki-reaper friendly and improve/fix. Works on Sun/Solaris 8, TCL 8.x and most UNIX flavors. (Don Libes: Thank you sooo much for Expect - you have no idea how many man-hours you save those who log into 30-100 routers, switches and servers per day.)

todo: Somebody adapt for Windows (maybe exec'ing PGP?)

The basic idea

  • Encrypt passwords using UNIX des encryption command (provides 56-bit encyption)
  • Use a single key for each password or file of passwords, provided by and known only to the user
  • The des key becomes the password to the program itself, and is only prompted for at startup
  • Decrypt the passwords needed, as needed, using the global variable key

Procedure to prompt for key - shameless pilfer from Mr. Libes' "Exploring Expect"

  • Takes pwprompt - ex. "Enter your password: "
  • Returns only user input stripped of carriage return
  • Tip: Suggest running this proc twice and comparing input to validate against typos only when encrypting passwords.
  • Tip: Encrypting the key with the key into the pwdir directory is useful also. Why? As a validation test when the user is just logging into a device, if catch utility_decrypt key.enc fails, the user entered the wrong key, so prompt again.
  • User password entry is not displayed when typed
 proc getpass pwprompt {
        set oldmode [stty -echo -raw]
        send_user "\n     $pwprompt"
        set timeout -1
        expect_user -re "(.*)\n"
        send_user "\n"
        eval stty $oldmode
        return $expect_out(1,string)
 }

Procedure to encrypt device passwords

  • Takes pd (password list to be encrypted) and filename (name of file for resulting encrypted password list) as input
  • Returns nothing
  • Format of the list of passwords (current and older generations by device type?) depends on how calling program needs them - suggest separated by \n character for readability
 proc utility_encrypt {pd filename} {
        global key HOME
        catch [exec echo "$pd" | des -e -k $key -b > $HOME/pwdir/$filename]
        return
 }

Procedure to decrypt device passwords

  • Takes filename (name of password file to decrypt)
  • Returns dpd (list of passwords in plaintext)
 proc utility_decrypt filename {
        global key HOME
        catch {exec cat $HOME/pwdir/$filename | des -d -b -k $key} dpd
        return $dpd
 }

You can use utility_encrypt in a setup program, and provide functionality that allows new passwords to be added to the encrypted files as they are implemented.

Lets assume the encrypted password files are organized by device type and separated with "\n". Then the mechanics of the program look something like this:

SAMPLE login proc

 proc foo_login_proc {device_name} {
        global key sid
        set spawn_id $sid($device_name)
        set decrypted_all [utility_decrypt foo_passwords.enc]
        for {set i 0} {$i <= [llength $decrypted_all]} {incr i} {
                set foo_pws($i) [lindex $decrypted_all $i]
        }
        ...
        #loop through foo_pws array using exp_send/expect until login successful...
        set i 0
        set pw $foo_pws($i)
        expect {
            "password for foo: "   {
                   exp_send "$pw\n"
                   exp_continue
                                   }
            "login successful"     {
                   interact
                                   {
            "invalid password"     {
                   incr i
                   set pw $foo_pws($i)
                   exp_continue
                                   {
            "other stuff"          {
                   ...
                                   } ;#eof, timeout, errors from device, etc.
               }
        ...
        exit
 }

SAMPLE Main

 #user launches program to log into a Foo systems Bar device ''device_name'':
 ...
 set user [exec whoami]
 set key [getpass "Enter password for $user: "]
 spawn -noecho telnet $device_name
 set sid($device_name) $spawn_id
 detect_device_prompt  ;# an Expect proc that detects this is a foo type device
                        # from it's prompt and launches the foo_login proc
 ...

[Start by looking at source protection.]

[Follow up by locating information about writing secure Tcl scripts]

Finally, consider using interactive prompting rather than hard coding passwords ...


Category Expect

Category Security