Hi,
Here is my first implementation of a function for PHP that decrypts an OPT-string from a yubikey. It works completely independent of yubico's servers. The only thing you need to change in the code is the AES-key of your yubikey. This code does
not check for OTP-replays! it's your job to check the counter and the sessioncounter!
Just put the code on your webserver together with the AES128-class you can download from here:
http://www.phpclasses.org/browse/file/17721.htmlway of calling: decode_yubistring($ystring,$secret_aes_key)
ystring: String from the yubikey
secret_aes_key: your 128 bit AES-key presented in HEX
returns array:publicID: The first part of the OPT-string. Normally the id of your yubikey
token: The last 32 yubikey characters of the OPT-string. This is going to be decrypted
token_bin: Token presented binary.
token_hex: Token presented in hex.
aeskey_bin: Your secret AES-key in binary format
aeskey_hex: Your secret AES-key in hex
token_decoded_bin: Decoded token in binary format
token_decoded_hex: Decoded token in hex
secretID_bin: Decrypted secret ID
secretID_hex: Decrypted secret ID in hex
counter: Decrypted number of times the yubikey has been powered up
counter_session: Decrypted number of times the yubikey has been pressed since last power up
timestamp: Decrypted number of 1/8sek since power up
random: Decrypted random number generated by the yubikey
crc: Decrypted CRC checksom generated by the yubikey
crc_ok=True if the checksum of the decrypted data is ok. Always check this!
Here comes my sourcecode:Code:
<html>
<head></head>
<body>
<form method="post" action="<?php echo $PHP_SELF; ?>">
Press your Yubikey:
<input type="text" name="yubistring" size="50">
<input type="submit" value="submit">
</form>
<?PHP
/*
PHP yubikey decryptor v0.1 by Alex Skov Jensen.
This program will ONLY decrypt data from your key. You have to check the crc_ok, counter and counter_session variables in order to very prevent OTP-replays!
You need to download the AES128 library from: http://www.phpclasses.org/browse/file/17721.html in order to use this program
Call decode_yubistring($yubistring,$aes_key) function. Function returnes an array with all decrypted information from the yubikey.
*/
// The secret AES key of your yubikey - the only parameter you need to set!
$secret_aes_key="802dce501d8547d6832a48c5da0c89af";
$t=decode_yubistring($_POST["yubistring"],$secret_aes_key);
while (list($key, $value) = each($t)) echo "$key=$value<br />\n";
function decode_yubistring($ystring,$secret_aes_key)
{
require_once('AES128.php');
$aes=new AES128();
$key=$aes->makeKey(pack('H*',$secret_aes_key));
$ydec=array();
if (strlen($ystring)>=32)
{
$ydec["token"]=substr($ystring,-32);
$ydec["publicID"]=substr($ystring,0,strlen($ystring)-32);
$ydec["token_bin"]=modhex_decode($ydec["token"]);
$ydec["token_hex"]=bin2hex($ydec["token_bin"]);
$ydec["aeskey_bin"]=pack('H*',$secret_aes_key);
$ydec["aeskey_hex"]=$secret_aes_key;
$ydec["token_decoded_bin"]=$aes->blockDecrypt($ydec["token_bin"], $key);
$ydec["token_decoded_hex"]=bin2hex($ydec["token_decoded_bin"]);
$ydec["secretID_bin"]=substr($ydec["token_decoded_bin"],0,6);
$ydec["secretID_hex"]=bin2hex($ydec["secretID_bin"]);
$ydec["counter"]=ord($ydec["token_decoded_bin"][7])*256+ord($ydec["token_decoded_bin"][6]);
$ydec["counter_session"]=ord($ydec["token_decoded_bin"][11]);
$ydec["timestamp"]=ord($ydec["token_decoded_bin"][10])*65536+ord($ydec["token_decoded_bin"][9])*256+ord($ydec["token_decoded_bin"][8]);
$ydec["random"]=ord($ydec["token_decoded_bin"][13])*256+ord($ydec["token_decoded_bin"][12]);
$ydec["crc"]=ord($ydec["token_decoded_bin"][15])*256+ord($ydec["token_decoded_bin"][14]);
$ydec["crc_ok"]=crc_check($ydec["token_decoded_bin"]);
}
return $ydec;
}
function crc_check($buffer)
{
$m_crc=0xffff;
for($bpos=0; $bpos<16; $bpos++)
{
$m_crc ^= ord($buffer[$bpos]) & 0xff;
for ($i=0; $i<8; $i++)
{
$j=$m_crc & 1;
$m_crc >>= 1;
if ($j) $m_crc ^= 0x8408;
}
}
return $m_crc==0xf0b8;
}
function modhex_decode($mstring)
{
$cset="cbdefghijklnrtuv";
$decoded="";
$hbyte=0;
for ($i=0; $i<strlen($mstring);$i++)
{
$pos=strpos($cset,$mstring[$i]);
if ($i/2-round($i/2))
{
$decoded.=chr($hbyte+$pos);
$hbyte=0;
} else $hbyte=$pos*16;
}
return $decoded;
}
?>
</body>
</html>
I hope that you can use it
Comments are welcome
Best regards,
Alex.