One-time passwords in Debian Wheezy with libpam-otpw

While public and private keys with decent pass-phrases are an excellent way of logging in securely to a remote system, it’s sometimes simply not feasible. Your Android device which normally does the job for you is out of battery, you are in a remote country with only a wired connection in a shady Internet café, or – <diety> forbid – your laptop was stolen while logged in and you desperately need to get on that system right now.

Anyway, one-time passwords, implemented as “opie” in earlier Debian versions, are now available as “otpw”. These allow you to generate securely stored single-use passwords that are safe to use “in the field”, and even have counter-measures to attacks like a keylogger opening several SSH connections to your host, trying to guess the last character of the one-time password before you type it.

The following guide will disable the use of ordinary passwords, keeping public/private key login enabled, followed by otpw if no key is provided. Thus, you can log in with your key if you have one, without being asked for a one-time password, but if you don’t provide one you get the password prompt.

To install this beauty, we need the pam module and the client program:

apt-get install libpam-otpw otpw-bin

Next, we need to configure /etc/pam.d/sshd to use the newly installed module. For my setup, I want to disable normal passwords, so I comment out the common-auth line, then add otpw.

# Standard Un*x authentication.
#@include common-auth

auth required
session optional

/etc/ssh/sshd_config needs some changes too. These are the relevant lines:

ChallengeResponseAuthentication yes
PasswordAuthentication no
PubkeyAuthentication yes
UsePrivilegeSeparation yes

The only really important line is the ChallengeResponseAuthentication one, which is what we’ll be using for otpw. Public keys and privilege separation are normally enabled by default, and as I mentioned I wanted to disable PasswordAuthentication, which covers the use of normal account passwords.

Because we changed the config, we need to restart sshd:

# /etc/init.d/ssh restart

Time to generate some one-time passwords:

$ otpw-gen --help
One-Time Password Generator v 1.2 -- Markus Kuhn
otpw-gen [options] | lpr
    -h <int>    number of output lines (default 60)
    -w <int>    max width of output lines (default 79)
    -s <int>    number of output pages (default 1)
    -e <int>    minimum entropy of each one-time password [bits]
            (low security: <30, default: 48, high security: >60)
    -p0        passwords from modified base64 encoding (default)
    -p1        passwords from English 4-letter words
    -f <filename>    destination file for hashes (default: ~/.otpw)
    -d        output debugging information

$ otpw-gen -h 20 -e 48 -p1
Generating random seed ...

If your paper password list is stolen, the thief should not gain
access to your account with this information alone. Therefore, you
need to memorize and enter below a prefix password. You will have to
enter that each time directly before entering the one-time password
(on the same line).

When you log in, a 3-digit password number will be displayed.  It
identifies the one-time password on your list that you have to append
to the prefix password. If another login to your account is in progress
at the same time, several password numbers may be shown and all
corresponding passwords have to be appended after the prefix
password. Best generate a new password list when you have used up half
of the old one.

Enter new prefix password: 
Reenter prefix password: 

Creating '~/.otpw'.
Generating new one-time passwords ...

OTPW list generated 2013-01-24 23:17 on slave

000 csce stub neat rope down  016 keep ness mine mock bile
001 pubs ever judo pert kemp  017 blip stan nana file shaw
002 ecsc bone hare hiss make  018 serb ills swam torn rump
003 page type owen dark lent  019 avid bran avid amps lair
004 unto hype fits bets loco  020 putt rout disc gogh bile
005 kits hard sums lime sore  021 hand rash rigs eels vain
006 foci path call spat tins  022 ship what loos chin pine
007 vote sold book gait name  023 yolk mont pubs main kilt
008 band cone draw mats fact  024 para must mala curd tire
009 oboe mill hair chad mont  025 pope slid olds ores dive
010 maps head frog eden teal  026 bony leas bcci jerk need
011 chas memo ives duck revd  027 womb pahl bird ruby naff
012 graf gosh rays roar pour  028 obey bear iona area gain
013 slab sons damn dell pass  029 sort jazz sega rigs onus
014 erik rags tact roar rags  030 lost lump cubs seat film
015 bees aces thee pump kant  031 aura road funk laid hibs

     !!! REMEMBER: Enter the PREFIX PASSWORD first !!!

Now you should be good to go. The next time you connect, you’ll be asked for one, or three, one-time passwords. Three passwords are requested when multiple logins happen simultaneously and other potentially suspicious situations. See /usr/share/doc/otpw-bin/otpw.html for details.

REMEMBER: The password you typed as your “prefix password” has to be entered before the password otpw asks for. If my prefix password was “hello”, and the application asked for password 031, I’d enter “helloauraroadfunklaidhibs”. Spaces can be typed if you want, but they are ignored.

This is what a typical login looks like for me.

$ ssh home.sweet.home -l bolt
Password 026: <This would be hellobonyleasbccijerkneed if my prefix password was still "hello">
Linux home.sweet.home 3.2.0-4-686-pae ..........

That’s about it. Remember there is no reason your prefix password needs to match your actual password on that system. They have no relation. It is a good idea to choose a different prefix password, especially if you happen to have “sudo” installed and set up for your user, so you’re not typing a password that can potentially make you root to log in from a shady web café. Someone just might take over your machine.


There is, at the time of writing, a bug in Debian Wheezy preventing the session optional line from displaying a count of your remaining one-time passwords upon a successful login. Until that is resolved, you might want to add the small snippet Wolfgang Kroener posted on the bug to your login scripts.


if [ "$SSH_TTY" -a -f $HOME/.otpw ]; then
  PW_LINES=$(wc -l <$HOME/.otpw)
  PW_USED=$(grep -- ---- $HOME/.otpw | wc -l)
  echo "OTPW $PW_USED/`echo $PW_LINES-2 | bc` used"

Leave a Reply

Your email address will not be published. Required fields are marked *