This is a detailed (including the necessary commands) description of the installation and functioning of the Sibyl. We assume you already have a working authentication server (the computer you want to log in to) and a different machine (the Sibyl) which acts as the oracle.
Preparing the Sibyl
Get a machine
First we need a 'Sibyl', which is a different machine from the server we want to log in to. We are using a Bifferboard as a proof of concept.
Install Linux on it
We assume a linux distro has been installed on the Sibyl (See the "Install Slackware on a bifferboard" manual if you are using a Bifferboard).
Generate the RSA pairs
Create two RSA key pairs in the Sibyl (we use 2048bit keys): the encryption
pair and the signing pair
Encryption/Decryption pair
Create the en/decryption pair with openssl. The private key will be named
decrypt and the public one decrypt.pub
Signing pair
Creating the signing pair with openssl. The private key will be named
sign and the public one sign.pub
Preparing the Authentication Server
Create the /etc/sibyl directory
(you probably need to be root to do this).
Copy the public keys (generated on the sibyl) into the /etc/sibyl directory.
Notice that the private keys *must never leave the Sibyl*. Their secrecy
is the basis for the security of this system.
Create the shadow file
This is where the user authentication tokens will be stored
(/etc/sibyl/shadow).
Encrypt (with crypt(3)) the user password
First, we need to encrypt the user password using the crypt function.
This function takes a password as a string, and a salt character array and
returns a printable ASCII string which starts with the same salt. The salt
serves for two purposes: to select which hashing algorithm is used, the
MD5-based one or the DES-based one, and to make life harder for
someone trying to guess passwords against a file containing many passwords;
without a salt, an intruder can make a guess, run crypt on it once, and
compare the result with all the passwords. With a salt, the intruder must run
crypt once for each different salt.
In this brief tutorial, we are going to use the MD5-based salt that
consists of the string $1$, followed by up to 8 characters and another $, and
the string. The result of crypt will be the salt, followed by a $ if the salt
didn't end with one, followed by 22 characters from the alphabet ./0-9A-Za-z,
up to 34 characters total. Every character in the key is significant.
For doing this we provides a short program (crypt.c) that uses the crypt
function with the password passed as an argument and the salt that can be
passed. If not, it will be (not very) randomnly generated.
Notice that the Sibyl's distribution includes a shadow2sibyl.pl scripts which
turns standard shadow files into Sibyl-enabled files. More on this in its
man page shadow2sibyl(n).
RSA-encrypt and base64 the above
The output of the crypt function will be RSA-encrypted using the decryption
public key and base64 encoded, that is: base64(RSA_encrypt(crypt(password, salt))).
This shall be stored without newlines, though (however we include them in this
tutorial for clarity).
Description of the shadow file
The format of each row (user authentication tokens) in the file
/etc/sibyl/shadow is:
In the example, the row will be:
The parts of the row are:
The Protocol
Startup
The Authentication Server (AS) connects to the Sibyl and expects to receive
a random nonce.
The Sibyl generates a nonce and sends it to the AS. In the example we use
the $RANDOM environment variable.
Fetch the authentication token
From the password database, the AS gets the real authentication token (p1)
Get the password
The AS grabs the password entered by the logging user.
Encrypt with crypt
The AS encrypts, using the crypt function, the password entered by the logging
user. We are going to use the crypt program provided by the example. We need the salt used in the first crypt:
RSA-encrypt
The AS encrypts $nonce_sibyl:$pass_crypted using the Sibyl's public key to get p2.
The result will be base64 encoded.
The AS sends $nonce_as;$p1;$p2 to the Sibyl.
Note that this nonce is different from the one received from the Sibyl.
Generate the nonce:
The AS sends $nonce_as;$p1;p2
Sibyl: decrypt p1
The Sibyl decrypts p1 (=u1)
Sibyl: decrypt p2
The Sibyl decrypts p2 (=u2)
Sibyl: check nonce
The Sibyl checks that u2 matches the pattern /^n:(.*)$/ and sets v1=$1.
Recall that n is the Sibyl's nonce.
Sibyl: check passwords match. Send answer
If u1=v1 then the Sibyl returns the message $nonce_as:1 signed with the
signing key. Otherwise, it returns the message m:0 signed with the same key.
In this example u1=v1 so we will send $nonce_as:1 (signed with the sign private key)
AS: receive answer and verify signature
The AS receives the signed message from the Sibil and checks if it is properly
signed
Check if answer was 'OK' or 'NOT OK'
As $nonce_as is equal to the number received in the first part of the message
(28145) and the second part of it is 1, the AS grants authentication. In any
other case, it is denied.