Jump to content

YubiKey� Authenticator


Zinthose
 Share

Recommended Posts

What is a YubiKey?

The device is a small USB device that is detected by the OS as a standard USB keyboard. Once activated the device sends a one time use password / authentication token. This little device is cool as hell , IMO of course.

Posted Image

So what can I use it for?

  • Allow a user to run an application as an administrator without the need to divulge the password.
  • Multifactor authentication by pairing the key with a user name and or password.
For more information goto: http://yubico.com

#cs - About
    This is a demo of a simple Yubikey authentication system.
    This requires an active internet connection to use the Yubico authentication servers.
    Further information on this technology can be aquired from [http://yubico.com]
    
    Coded by Zinthose [AutoIt Forumns - http://www.autoitscript.com/forum]
#ce

#Region ; - Yubico Yubikey Authentication [Online Version]
    #include <INet.au3>
    
    Global Const $YUBIKEY_OK                    = "OK";                     <-- The OTP is valid.
    Global Const $YUBIKEY_BAD_OTP               = "BAD_OTP";                <-- The OTP is invalid format.
    Global Const $YUBIKEY_REPLAYED_OTP          = "REPLAYED_OTP";           <-- The OTP has already been seen by the service.
    Global Const $YUBIKEY_BAD_SIGNATURE         = "BAD_SIGNATURE";          <-- The HMAC signature verification failed. (Not yet implemented)
    Global Const $YUBIKEY_MISSING_PARAMETER     = "MISSING_PARAMETER";      <-- The request lacks parameter given by key info.
    Global Const $YUBIKEY_NO_SUCH_CLIENT        = "NO_SUCH_CLIENT";         <-- The request id does not exist.
    Global Const $YUBIKEY_OPERATION_NOT_ALLOWED = "OPERATION_NOT_ALLOWED";  <-- The request id is not allowed to verify OTPs.
    Global Const $YUBIKEY_BACKEND_ERROR         = "BACKEND_ERROR";          <-- Unexpected error in our server. Please contact us if you see this error. (support@yubico.com)
    Global Const $YUBIKEY_PARSE_FAIL            = "PARSE_FAIL";             <-- Corupted Reply: Check Proxy, Network, ect.  This can also be cause if the Yubico net API changed. (http://yubico.com/developers/api)
    
    ;## Get the Key's ID
        Func _Yubikey_GetID($OTP)
            Local $ID, $Key, $Len
            
            ;## Validate Parameters
                If Not IsString($OTP)   Then Return SetError(1, 0, $YUBIKEY_BAD_OTP)
                $Len = StringLen($OTP)
                If $Len < 44            Then Return SetError(2, 0, $YUBIKEY_BAD_OTP)
                
            ;## Extract $ID
                $ID     = StringMid($OTP, $Len - 43, 12)
                
                Return $ID
        EndFunc
    
    ;## Validate the Yubikey One time password
        Func _Yubikey_Validate($OTP, $ID = Default)
            Local $URL, $Result
            Local Const $Pattern = "(?i)(?m)^status=(.+)"
            
            ;## Validate Parameters
                If $ID = Default        Then $ID = 87
                If Not IsNumber($ID)    Then Return SetError(1, 0, $YUBIKEY_NO_SUCH_CLIENT)
                If Not IsString($OTP)   Then Return SetError(2, 0, $YUBIKEY_BAD_OTP)
                If StringLen($OTP) <> 44 Then Return SetError(3, 0, $YUBIKEY_BAD_OTP)
            
            ;## Connect to the Yubico Servers to Validate
                $URL = 'https://api.yubico.com/wsapi/verify?otp=' & _INetExplorerCapable($OTP) & '&id=' & _INetExplorerCapable($ID)
                $Result = _INetGetSource($URL)
            
            ;## Return Results
                If StringRegExp($Result, $Pattern) = 0 Then Return SetError(4, 0, $YUBIKEY_PARSE_FAIL)
                $Result = StringRegExp($Result, $Pattern, 1)
            
                Return $Result[0]
        EndFunc
            
#EndRegion

#Region ; - Example
    Dim $OneTimePassword, $KeyID, $AuthenticationResult
    
    ;## Get the Yubikey Value 
        $OneTimePassword = InputBox("Yubikey Authenticator", "Enter Yubikey OTP:", "", "*")
    
    ;## Get the Key's Unique ID (This can be tied to a user's account)
        $KeyID = _Yubikey_GetID($OneTimePassword)
    
    ;## Validate / Authenticate the The OneTimePassword
        $AuthenticationResult = _Yubikey_Validate($OneTimePassword)

    ;## Display Results
        MsgBox(4096, "Yubikey Result", "ID = " & $KeyID & @CRLF & "Result = " & $AuthenticationResult)
    
#EndRegion

--- TTFN

Link to comment
Share on other sites

  • 9 months later...
  • 7 years later...

It has been some years since this was posted. I had made my own just now and I thought I would share it here than make a whole new thread:

#include <Crypt.au3>

Global $otp, $APIid = 00000000, $error, $CustSalt = '7F34E3F39F7967B38A9CEB3C3EE55F17BF9552F8F7A5B74', $AuthorisedHashedPubID = '0x6F25B171D3563C000F75455EAFFA1AA967EAB605'

; Get your API ID ($APIid) by registering for an API key: https://upgrade.yubico.com/getapikey/
; Use your own custom salt value above so that all the hashes will be entirely unique to your implementation.

$otp = InputBox('Yubikey OTP Request', 'Press the OTP Button on your Yubikey', Default, '*') ; Obtain the OTP from the user, by them pressing the button on their Yubikey that is inserted.
$nousedonce = StringTrimLeft(HashThis(StringReplace(Random(), '.', '') & @MSEC & StringReplace(Random(), '.', '') & StringReplace(Random(), '.', '') & @SEC & @MSEC), 2) ; This is the "number, used once" which actually is random data, not a number.


;;;;; Prep area, uncomment to generate a working hash to check the person's Yubikey "Public Identity" prefix to generate a salted hash you can check in the future to authenticate their Yubikey
;~ ClipPut(HashThis('ccccccjlgpht')) ; Paste the first 12 characters of a genuine Yubikey OTR that you wish to authorise to access this program and copy the resulting salted hash
;~ Exit
;;;;;

$url = 'https://api.yubico.com/wsapi/2.0/verify?otp=' & $otp & '&id=' & $APIid & '&nonce=' & $nousedonce & '&timestamp=1' ; Constructing the URL needed to check with the remote server about a Yubikey's OTP output.
$results = InetRead($url, 1) ; Sending the request to the API server.

If Not @error Then
    $results = BinaryToString($results)
    $split = StringSplit($results, @CRLF, 3) ; Breaking the resulting feedback from the API server up into lines (array rows) so parameters can be ensured they start from the beginning of each line.

    If StringInStr($results, 'otp=' & $otp) And StringInStr($results, 'nonce=' & $nousedonce) And StringInStr($results, 'status=OK') Then ; If OTP and nonce that were sent to server are the same ones returned & status is OK, continue validation.

        For $a In $split
            If StringInStr($a, 'otp=', 1) Then ; If this row of the array contains the otp parameter (it starts at the beginning of the string) then...
                $a = StringReplace($a, 'otp=', '') ; Strip away the parameter prefix of "otp="
                If HashThis(StringMid($a, 1, 12)) = $AuthorisedHashedPubID Then ; If the newly salted & hashed Yubikey's Public ID matches the existing salted hash of the authorised user, then do the immediately following thing...
                    MsgBox(0, 'SUCCESS', 'Successfully authenticated the authorised user''s Yubikey')
                Else ; If we got here, the OTP that was generated was valid but the particular Yubikey was not one authorised for use with this program, so instead, do the following thing.
                    MsgBox(0, 'Error', 'While the Yubico OTP was validated as genuine,' & @CRLF & 'this Yubikey is not authorised for access.')
                EndIf
            EndIf
        Next

    ElseIf Not StringInStr($results, 'status=OK') Then ; If the status is anything other than "OK" there is a problem with the OTP that was generated, perhaps it was an old used one? etc.

        For $a In $split
            If StringInStr($a, 'status=', 1) Then $error = StringReplace($a, 'status=', '') ; set the error code supplied by the API server in the $error variable.
        Next

        MsgBox(0, 'Error', 'Yubico authentication error: ' & $error) ; Display the error to the user.
    EndIf

Else
    MsgBox(0, 'Error', 'Error accessing Yubico API address.') ; There was a problem accessing the API server, perhaps an internet problem or SSL problem.
EndIf


Func HashThis($_input) ; Simply does the salted hashing and provides the result
    $_hash = StringTrimLeft(_Crypt_HashData($CustSalt & $_input, $CALG_SHA1), 0)
    Return $_hash
EndFunc   ;==>HashThis

My goal was to not have the required public ID stored in the source of the program, yet be able to check when it is the correct one.

Link to comment
Share on other sites

I don't think you understand what a Yubikey is. It is not just something that spits out a password or something. It is capable of doing that as one of it's features, but it is a cutting edge cryptographic security token. It has U2F (universal 2-factor authentication), various OTP (one-time password) capabilities, OpenPGP key based operations like decryption and signing from within the unit, smartcard operations like digital signature authentication, physical access, etc etc. You can also set in the modern ones the QR codes to your 2-factor using services so that rather than have an app on your computer or phone with all the private data, your private data is in the Yubikey and the resulting one-time codes are accessible at the time they are needed with the private keys never leaving the device.

Link to comment
Share on other sites

I'd rather stick with the 3 gram practically bomb proof sealed black-box design of the Yubikey which is designed in all aspects to keep the encryption private keys stuck inside never to be released.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...