Yubikey – IV – Accès en VBA – 3 – Programmation de la Yubikey

Nous avons vu dans les articles précédents comment accéder à la Yubikey pour lire les informations qui s’y trouvent ou encore lui demander de générer une signature HMAC-SHA1.

Je vais clore cette partie sur la Yubikey et le VBA en montrant comment écrire dans la Yubikey, pour la programmer.

A l’aide de ces différentes parties que j’ai abordé, vous aurez tous les éléments pour par exemple, réaliser une petite application VBA permettant de gérer un stock de Yubikey pour les programmer, en faire des doubles, gérer leur attribution. L’avantage par rapport à une base de données est que lorsque que l’on ne gère pas un stock très important de Yubikey, c’est une solution facile et efficace à mettre en place.
Vous pouvez avoir accès à un tableau contenant toutes les informations relatives aux Yubikey sous forme d’une feuille Excel, ce qui permet de faire des éditions papiers facilement et se prémunir contre une catastrophe comme la perte des moyens informatiques centraux et ne plus être en possibilité de faire des doubles par exemple.
Je ne rentrerai pas dans les explications sur les procédures à mettre en place pour gérer la sécurité du système de gestion des Yubikey s’il repose sur Excel, nous somme en dehors des objectifs de cet article, mais c’est une question fondamentale à se poser et sur laquelle j’ai été amené à me pencher.

Revenons donc aux aspects techniques et laissons les aspects organisationnels.

Préparation d’Excel

Je suppose que vous disposez d’un Excel déjà paramétré pour lire le contenu d’une Yubikey. La bibliothèque de Yubico ‘Yubikey Client API’ doit être installée et accessible.

Mais, cette bibliothèque ne suffit pas. En effet, elle est spécialisée dans la lecture d’une Yubikey. Pour écrire, il faut avoir recours à une autre bibliothèque qui se nomme ‘Windows Server COM API’.

Voici le lien chez Yubico qui permet de récupérer les dernières versions des bibliothèques clientes et serveur : https://developers.yubico.com/windows-apis/Releases/

Selon vos besoins, vous récupérez la 32 ou 64 bits, mais pour Excel il est nécessaire de prendre la 32 bits quelque soit votre système (32 ou 64 bits). Ce point a été abordé dans l’article sur la lecture du numéro de série en VBA.

Au moment de la rédaction de cet article, le fichier est en version 2.3 et se nomme yubikey-configuration-API_x86-2.3.msi.

Le fichier téléchargé, il s’installe de la même façon que la bibliothèque ‘Yubikey Client API’, vu dans l’article sur la lecture du numéro de série.

Lancer ensuite Excel et suivre de nouveau la même procédure, menu Développeur/Visual Basic/Outils/Références. Normalement les bibliothèques clientes et serveur de Yubico doivent apparaître de le bas de la liste des Références disponibles :

ecriture-Yubikey-1Cocher les deux bibliothèques, ‘Yubico Client API 1.0’ et ‘Yubico YubiKcom 2.3’, puis faire ‘OK’.

Détection de l’insertion de la clef

Nous allons utiliser une possibilité de la bibliothèque YubiKcom, qui est de gérer des événements, notamment l’insertion et le retrait de la Yubikey.

Dans une feuille de calcul vierge, on passe dans le menu Visual Basic et on crée un UserForm le plus simple qui ressemble à celui-ci :

ecriture-Yubikey-2Il comporte un seul objet qui est une zone de saisie de texte et que j’ai nommé Txtnumstock.
L’objectif va être :

  • Si une Yubikey est insérée, une boite de dialogue s’affiche avec écrit « Insérée », et le numéro de série de la clef est rempli dans la zone de texte.
  • Si une Yubikey est retirée, une boite de dialogue s’affiche avec écrit « Retirée », et la zone de texte est effacée.

Voici le code correspondant, que l’on va ensuite détailler :

Dim WithEvents cle As YubiKcomLib.YubiKeyConfig
Dim WithEvents obj As YubiClientAPILib.YubiClient
 
 
'*****************************************
'* On insère la Yubikey dans le  port USB
'*****************************************
Private Sub cle_ykInserted()
Dim numserieh As String
 
    MsgBox ("Insérée")
        If obj.isInserted = ycRETCODE_OK Then
             retour = obj.readSerial(ycCALL_BLOCKING)
            If retour = ycRETCODE_OK Then
                obj.dataEncoding = ycENCODING_UINT32
                numserieh = obj.dataBuffer
                Txtnumstock.Value = numserieh
            Else
                MsgBox ("Erreur ycRETCODE")
             End If
        End If
End Sub
 
'*************************************
'* On retire la Yubikey du port USB
'**************************************
Private Sub cle_ykRemoved()
     MsgBox ("Retirée")
     Txtnumstock.Value = ""
End Sub
 
 
Private Sub UserForm_Initialize()
    Set cle = New YubiKcomLib.YubiKeyConfig
    Set obj = New YubiClientAPILib.YubiClient
 
    cle.ykEnableNotifications = True
 
End Sub

On commence  par déclarer l’utilisation des deux bibliothèques :

Dim WithEvents cle As YubiKcomLib.YubiKeyConfig
Dim WithEvents obj As YubiClientAPILib.YubiClient

La première dans l’objet cle pour la gestion de l’événementiel
La seconde dans l’objet obj pour accéder au numéro de série.

Lorsque le formulaire est initialisé, à son affichage, on crée les objets cle et obj, et on arme le gestionnaire d’événement de la bibliothèque YubiKcom :

    cle.ykEnableNotifications = True

On dispose alors de deux méthodes correspondant à l’insertion et au retrait de la clef :

Private Sub cle_ykRemoved()

et

Private Sub cle_ykInserted()

Lorsque la Yubikey est insérée la méthode cle_ykInserted est déclenchée. On vérifie que la clef est correctement détectée :

       If obj.isInserted = ycRETCODE_OK Then

puis on récupère le numéro de série pour l’afficher :

             retour = obj.readSerial(ycCALL_BLOCKING)
            If retour = ycRETCODE_OK Then
                obj.dataEncoding = ycENCODING_UINT32
                numserieh = obj.dataBuffer
                Txtnumstock.Value = numserieh

Le fichier d’exemple est téléchargeable : détection-insertion

Programmation de la Yubikey

Nous allons maintenant utiliser la bibliothèque YubiKcom pour programmer la clef. Je vais prendre comme exemple la programmation du slot 1 pour qu’un mot de passe statique soit enregistré lorsque l’on appuie sur la pastille dorée.

Le principe est le suivant. On va positionner deux variables qui vont permettre de spécifier que l’on veux programmer un mot de passe statique, avec codage en scancode. (On pourrait le faire aussi en modhex).
Les variables en question sont :

  • CFGFLAG_STATIC_TICKET qui doit prendre la valeur False
  • CFGFLAG_SHORT_TICKET qui doit prendre la valeur True

Pur voir la liste des combinaisons avec leurs effets, on peut se référer au forum suivant de chez Yubico : http://forum.yubico.com/viewtopic.php?f=30&t=959

Ensuite on convertit sa chaine de caractères en scan codes. On prend un maximum de 38 caractères qui seront éclatés en trois blocs, qui correspondent à des « registres » de la Yubikey :

  • Le 1er bloc de 16 caractères (32 de long en scancode) dans ykStaticID
  • Le  2ème bloc de 6 dans ykUID
  • Le  3ème bloc de 16 dans ykKey

En envoie ensuite l’ordre d ‘écriture à la Yubikey.

Voici une fonction de programmation de la Yubikey qui réalise cela :

' *******************************************************************************************
'* Programmation d'un slot en static Password
'********************************************************************************************
'* Premier paramètre, slot à programmer, 1 ou 2
'* Deuxième paramètre, mot de passe
' pour le codage du mot de passe, (Trouvé sur http://forum.yubico.com/viewtopic.php?f=30&t=959)
' Standard OTP, modhex encoded: CFGFLAG_STATIC_TICKET = FALSE, CFGFLAG_SHORT_TICKET = FALSE
' Static OTP, modhex encoded: CFGFLAG_STATIC_TICKET = TRUE, CFGFLAG_SHORT_TICKET = FALSE
' Truncated static OTP, modhex encoded : CFGFLAG_STATIC_TICKET = TRUE, CFGFLAG_SHORT_TICKET = TRUE
' Static OTP, scancode mode : CFGFLAG_STATIC_TICKET = FALSE, CFGFLAG_SHORT_TICKET = TRUE
Function programStatic(slot As Integer, chaine As String)
    Dim Passwd As String
    Dim slot2 As Boolean
    ' La variable slot2 vaut True ou False pour spécifier si on programme ou non le second slot de la YubiKey
    If slot = 2 Then slot2 = True Else slot2 = False
 
    cle.ykFlagProperty(ykFLAG_SECOND_CONFIG) = slot2 ' Est-ce que l'on programme ou non le second slot.
    cle.ykFlagProperty(ykFLAG_APPEND_CR) = True      ' On ajoute le retour chariot après l'envoie du mot de passe
    cle.ykFlagProperty(ykFLAG_STATIC_TICKET) = False ' Mode Static avec encodage scancode
    cle.ykFlagProperty(ykFLAG_SHORT_TICKET) = True
    cle.ykFlagProperty(ykFLAG_SERIAL_API_VISIBLE) = True ' Pour ne pas masquer le n° de série
    cle.ykFlagProperty(ykFLAG_SERIAL_USB_VISIBLE) = True
    cle.ykFlagProperty(ykFLAG_MAN_UPDATE) = True ' Possibilité de maj du mdp pour l'utilisateur
     
      chaine = convScan(chaine)                       ' Conversion en Scancode
    ' les 38 caractères sont découpé en trois blocs pour les programmer dans dans la Yubikey.
    ' 1er bloc de 16 (32 de long en scancode) dans ykStaticID
    ' 2ème bloc de 6 dans ykUID
    ' 3ème bloc de 16 dans ykKey
    chaine = Left(chaine, 76) ' controle : on ne prend que 38 caractère (76 scancodes)
    If Len(chaine) > 32 Then
        cle.ykStaticID = Mid(chaine, 1, 32)
        If Len(chaine) > 44 Then
            cle.ykUID = Mid(chaine, 33, 44)
            cle.ykKey = Mid(chaine, 45, Len(chaine) - 44)
        Else
            cle.ykUID = Mid(chaine, 33, Len(chaine) - 32)
        End If
    Else
        cle.ykStaticID = chaine
        cle.ykKey = ""
    End If
 
     programStatic = cle.ykProgram ' Programmation de la clé

End Function

A toutes fin utiles, un ensemble de fonctions qui peuvent être utiles pour manipuler les Yubikey.
Voici une fonction de conversion chaine -> scancode

Function convScan(chaine)
    Dim mapping(254) As String
    Dim i As Integer
    Dim resultat As String
 
    mapping(48) = "a7" '0
    mapping(49) = "9e" '1
    mapping(50) = "9f" '2
    mapping(51) = "a0" '3
    mapping(52) = "a1" '4
    mapping(53) = "a2" '5
    mapping(54) = "a3" '6
    mapping(55) = "a4" '7
    mapping(56) = "a5" '8
    mapping(57) = "a6" '9

    mapping(65) = "94" 'A
    mapping(66) = "85" 'B
    mapping(67) = "86" 'C
    mapping(68) = "87" 'D
    mapping(69) = "88" 'E
    mapping(70) = "89" 'F
    mapping(71) = "8a" 'G
    mapping(72) = "8b" 'H
    mapping(73) = "8c" 'I
    mapping(74) = "8d" 'J
    mapping(75) = "8e" 'K
    mapping(76) = "8f" 'L
    mapping(77) = "B3" 'M
    mapping(78) = "91" 'N
    mapping(79) = "92" 'O
    mapping(80) = "93" 'P
    mapping(81) = "84" 'Q
    mapping(82) = "95" 'R
    mapping(83) = "96" 'S
    mapping(84) = "97" 'T
    mapping(85) = "98" 'U
    mapping(86) = "99" 'V
    mapping(87) = "9d" 'W
    mapping(88) = "9b" 'X
    mapping(89) = "9c" 'Y
    mapping(90) = "9a" 'Z
    
    mapping(97) = "14"  'a
    mapping(98) = "05"  'b
    mapping(99) = "06"  'c
    mapping(100) = "07" 'd
    mapping(101) = "08" 'e
    mapping(102) = "09" 'f
    mapping(103) = "0a" 'g
    mapping(104) = "0b" 'h
    mapping(105) = "0c" 'i
    mapping(106) = "0d" 'j
    mapping(107) = "0e" 'k
    mapping(108) = "0f" 'l
    mapping(109) = "33" 'm
    mapping(110) = "11" 'n
    mapping(111) = "12" 'o
    mapping(112) = "13" 'p
    mapping(113) = "04" 'q
    mapping(114) = "15" 'r
    mapping(115) = "16" 's
    mapping(116) = "17" 't
    mapping(117) = "18" 'u
    mapping(118) = "19" 'v
    mapping(119) = "1d" 'w
    mapping(120) = "1b" 'x
    mapping(121) = "1c" 'y
    mapping(122) = "1a" 'z
    
 
    For i = 1 To Len(chaine)
        resultat = resultat & mapping(Asc(Mid(chaine, i, 1)))
    Next i
    convScan = resultat
 
End Function

A titre d’illustration, une fonction de programmation en HMAC-SHA1 :

' *******************************************************************************************
'* Programmation d'un slot en HMAC-SHA1 (Challenge/reponse)
'********************************************************************************************
'* Premier paramètre, slot à programmer, 1 ou 2
'* Deuxième paramètre, phrase secrète

Function programHmac(slot As Integer, chaine As String)
    Dim Passwd As String
    Dim slot2 As Boolean
    ' La variable slot2 vaut True ou False pour spécifier si on programme ou non le second slot de la YubiKey
    If slot = 2 Then slot2 = True Else slot2 = False
 
    Passwd = chaine ' C'est une clef secrète en Hexadécimal
    
    cle.ykFlagProperty(ykFLAG_SECOND_CONFIG) = slot2
    cle.ykFlagProperty(ykFLAG_STATIC_TICKET) = False
    cle.ykFlagProperty(ykFLAG_SHORT_TICKET) = False
    cle.ykFlagProperty(ykFLAG_CHAL_HMAC) = True
    cle.ykFlagProperty(ykFLAG_APPEND_CR) = False
    cle.ykFlagProperty(ykFLAG_CHAL_BTN_TRIG) = False
    cle.ykFlagProperty(ykFLAG_HMAC_LT64) = True ' L'entrée est de taille Variable (autre option, fixe 64 bits)
    cle.ykKey = Passwd
    programHmac = cle.ykProgram
 
End Function

Une fonction de génération d’une pharse secrète HMAC aléatoire :

'*******************************************************************************************
'* Génération d'une série Hexadécimale pour clef secrète HMAC
'********************************************************************************************
Function clehmac(longueur As Integer) As String
    Dim chaine, resultat As String
    Dim i, alea As Integer
 
    Randomize
 
    For i = 1 To longueur
        alea = (Int(255) * Rnd) + 1
        resultat = resultat & Hex(alea)
    Next i
    clehmac = LCase(resultat)
End Function

Une fonction de conversion en Modhex :

Function convModhex(chaine)
Dim mapping(50) As String
Dim i, code As Integer
Dim resultat As String
 
    mapping(0) = "c"
    mapping(1) = "b"
    mapping(2) = "d"
    mapping(3) = "e"
    mapping(4) = "f"
    mapping(5) = "g"
    mapping(6) = "h"
    mapping(7) = "i"
    mapping(8) = "j"
    mapping(9) = "k"
    mapping(10) = "l"
    mapping(11) = "n"
    mapping(12) = "r"
    mapping(13) = "t"
    mapping(14) = "u"
    mapping(15) = "v"
 
    For i = 1 To Len(chaine)
        code = Asc(Mid(chaine, i, 1))
        If code >= 48 And code <= 57 Then code = code - 48 End If If code >= 97 And code <= 102 Then 'lettre a -> f
            code = code - 87
        End If
        If code > 15 Then
            MsgBox ("Erreur de chaine, ca n'est pas que de l'hexadécimal : " & chaine)
            code = 0
        End If
        resultat = resultat & mapping(code)
    Next
    convModhex = resultat
End Function
Posts relatifs

Laisser un commentaire


NOTE - Vous pouvez utiliser les éléments et attributs HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">