Serveur et client securiser
Publié : jeu. 09/mai/2013 16:40
Bonjours à tous !
Voici le code source d'un serveur et d'un client sécuriser avec le chiffrement RSA et RC5, avec authentification HMAC SHA1, multi-threader.
Il s'agit d'un code de base pour que toute personne souhaitant créer une application réseau sécuriser, avec sont propre protocole puisse le faire simplement, le code est commenter.
REMARQUE dans ces codes, l'identifiant est "Jerome", et le Mot de passe est SHA1("Password").
Code source du serveur :
Code source du client :
Dites moi ce que vous en pensez, ci cela vous sert.
Cordiallement Caussat Jerome.
Voici le code source d'un serveur et d'un client sécuriser avec le chiffrement RSA et RC5, avec authentification HMAC SHA1, multi-threader.
Il s'agit d'un code de base pour que toute personne souhaitant créer une application réseau sécuriser, avec sont propre protocole puisse le faire simplement, le code est commenter.
REMARQUE dans ces codes, l'identifiant est "Jerome", et le Mot de passe est SHA1("Password").
Code source du serveur :
Code : Tout sélectionner
;-Base d'un serveur multi-threader securiser avec openssl:
;Necessaire : OPENSSL installer dans C:\OPENSSL\BIN
;-Fonctionnement du serveur :
;-1 Le client initialise la connection securiser, il ne peut faire rien d'autre sans cela.
;-2 Le serveur confirme la connection securiser
;REMARQUE : La connection sécuriser est initialiser avec du RSA, et ensuite ce poursuit en RC5
;-3 Le client envoi sont identifiant
;-4 Le serveur confirme l'identifiant et envoi un SALT pour l'opération de validation du mot de passe (HMAC SHA1)
;-5 Le client envoi le resultat de l'opération de validation de sont mot de passe avec le salt (HMAC SHA1)
;-6 Le serveur confirme l'authentification
;-7 Le client peut effectuer des action en tant qu'utilisateur authentifier (içi LOGOUT ou QUIT....)
;-8 Le Serveur repond au demande d'action...
;-9 Le client indique la fin de la session.
;-10 Le serveur confirme, et deconnecte, supprimme le THREAD du client.
;REMARQUE : Si le client tarde à envoyer une commande, le serveur coupe la connection et supprime le THREAD du client (au bout d'une minute dans ce code)
;-Protocole :
;Etablisement de la connection securiser :
;C : TUNN CKEY
;S : TOK SKEY | TNO (TOK = Initialisation de la connection securiser ok, TNO = pas ok et pas implementer..)
;Identification :
;C : USER LOGIN
;S : UOK HMACKEY | UNO (UOK = Identifiant existant, UNO = Identifiant inéxistant)
;C : PASS HMACRESULT
;S : POK | PNO (POK = Mot de passe corecte, PNO = Mot de passe incorecte)
;Deconnection :
;C : LOUT
;S : LOK
;Quitter :
;C : QUIT
;S : QOK
;-Constantes pour RC5
;crypt provider:
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"
#MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"
#MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider v1.0"
#MS_AES_PROV ="Microsoft AES Cryptographic Provider v1.0"
#MS_RSA_PROV ="Microsoft RSA Signature Cryptographic Provider v1.0"
;Crypt-Constants
#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 24576 ;$6000
#ALG_CLASS_HASH = 32768 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 2048
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8
; Valid hashing algorithms:
;
#ALG_SID_HMAC = 9
#ALG_SID_MAC = 5
#ALG_SID_MD2 = 1
#ALG_SID_SHA = 4
#ALG_SID_SHA1 = 4
#ALG_SID_SSL3SHAMD5 = 8
#ALG_SID_DES = 1
#ALG_SID_3DES = 3
#ALG_SID_3DES_112 = 9
#CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
#CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
#CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
#CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
#CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CALG_DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_DES
#CALG_3DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES
#CALG_3DES2 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES_112
;-Fin de Constantes pour RC5
;-debut de variables
Global ClientID.l,SEvent.l, quit.l=0
Global path.s="C:\openssl\bin\"
Global currentdir.s=GetPathPart(ProgramFilename())
;-fin de variables
Procedure.s hextoasc(entrer.s)
For a = 1 To Len(entrer.s) Step 2
sortie.s+Chr(Val("$"+Mid(entrer.s,a,2)))
Next a
ProcedureReturn sortie.s
EndProcedure
Procedure.s hmac_sha1(key.s,msg.s)
If(Len(key.s)>64); Si key est plus grand que 64 octets...
key.s=SHA1Fingerprint(@key.s,Len(key.s))
key.s=hextoasc(key.s)
EndIf
key.s=LSet(key.s,64,Chr(0));Il faut que la clef soit de 64 octets, on ajoute donc autant de fois que necessaire le caractères ASCII 0.
ipad.s=LSet(ipad.s,64,Chr($36));On prépare la variable ipad (64 fois le caractère $36)
opad.s=LSet(opad.s,64,Chr($5c));On prépare la variable opad (64 fois le caractère $5c)
For a=1 To 64
opadt.s+Chr(Asc(Mid(opad,a,1))!Asc(Mid(key,a,1))); on prépare la variable opadt (opad XOR key)
ipadt.s+Chr(Asc(Mid(ipad,a,1))!Asc(Mid(key,a,1))); on prépare la variable ipadt (ipad XOR key)
Next a
ipadt.s+msg.s;on ajoute le message a ipad.
hipad.s=SHA1Fingerprint(@ipadt.s,Len(ipadt.s))
opadt.s+hextoasc(hipad.s)
hopad.s=SHA1Fingerprint(@opadt.s,Len(opadt.s))
ProcedureReturn hopad.s
EndProcedure
Procedure.s rc5encrypt(String$, Key$);-Chiffrement RC5 grce à l'API WINDOWS
Protected *Buffer
Protected DataLength.l
Protected hProv
Protected hHash
Protected result.s
*Buffer = AllocateMemory(Len(String$) * 2 + 64)
DataLength.l = Len(String$)
PokeS(*Buffer, String$)
If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
EndIf
If hProv
CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
If hHash
CryptHashData_(hHash, @Key$, Len(Key$), 0)
CryptDeriveKey_(hProv, #CALG_3DES2, hHash, #CRYPT_EXPORTABLE, @hKey)
If hKey
If CryptEncrypt_(hKey, 0, #True, #Null, *Buffer, @DataLength, Len(String$) * 2 + 64)
EndIf
CryptDestroyKey_(hKey)
EndIf
CryptDestroyHash_(hHash)
EndIf
CryptReleaseContext_(hProv, 0)
EndIf
result.s = Space(DataLength * 3)
Base64Encoder(*Buffer, DataLength, @result, DataLength * 3)
FreeMemory(*Buffer)
ProcedureReturn result
EndProcedure
Procedure.s rc5decrypt(String$, Key$);-DéChiffrement RC5 grce à l'API WINDOWS
Protected *Buffer
Protected DataLength.l
Protected hProv
Protected hHash
Protected result.s
*Buffer = AllocateMemory(Len(String$) * 2 + 64)
DataLength.l = Base64Decoder(@String$, Len(String$), *Buffer, Len(String$) * 2 + 64)
If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
EndIf
If hProv
CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
If hHash
CryptHashData_(hHash, @Key$, Len(Key$), 0)
CryptDeriveKey_(hProv, #CALG_3DES2, hHash, #CRYPT_EXPORTABLE, @hKey)
If hKey
If CryptDecrypt_(hKey, 0, #True, 0, *Buffer, @DataLength)
result.s = PeekS(*Buffer, DataLength)
EndIf
CryptDestroyKey_(hKey)
EndIf
CryptDestroyHash_(hHash)
EndIf
CryptReleaseContext_(hProv, 0)
EndIf
FreeMemory(*Buffer)
ProcedureReturn result
EndProcedure
Procedure.s gen_key(taille);-Générateur de string pseudo-aléatoire (Je n'utilise pas toute la table ASCII, car cela pose des problème avec les caractères spéciaux)
Protected a.l,sortie.s
For a=1 To taille
sortie.s+Chr(CryptRandom(110)+33)
Next a
ProcedureReturn sortie.s
EndProcedure
;-Procedure RSA:
Procedure.s rsa_openssl_gen(taille,dossier.s)
RunProgram(path.s+"openssl.exe","rand -out random.bin "+Str(taille),dossier.s,#PB_Program_Wait| #PB_Program_Hide)
RunProgram(path.s+"openssl.exe","genrsa -rand random.bin -out mykey.pem "+Str(taille),dossier.s,#PB_Program_Wait| #PB_Program_Hide)
RunProgram(path.s+"openssl.exe","rsa -in mykey.pem -out mycert.pem -outform PEM -pubout",dossier.s,#PB_Program_Wait| #PB_Program_Hide)
DeleteFile(dossier.s+"random.bin")
EndProcedure
Procedure.s rsa_openssl_encrypt(entrer.s,dossier.s)
OpenFile(1,dossier.s+"entrer.dat")
WriteData(1,@entrer.s,Len(entrer.s))
CloseFile(1)
RunProgram(path.s+"openssl.exe","rsautl -encrypt -in entrer.dat -inkey mycert.pem -pubin -out coder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
RunProgram(path.s+"openssl.exe","base64 -in coder.dat -out base64.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
OpenFile(1,dossier.s+"base64.dat")
sortie.s=Space(Lof(1))
ReadData(1,@sortie.s,Lof(1))
CloseFile(1)
DeleteFile(dossier.s+"entrer.dat")
DeleteFile(dossier.s+"coder.dat")
DeleteFile(dossier.s+"base64.dat")
ProcedureReturn sortie.s
EndProcedure
Procedure.s rsa_openssl_decrypt(entrer.s,dossier.s)
OpenFile(1,dossier.s+"entrer.dat")
WriteData(1,@entrer.s,Len(entrer.s))
CloseFile(1)
RunProgram(path.s+"openssl.exe","base64 -d -in entrer.dat -out coder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
RunProgram(path.s+"openssl.exe","rsautl -decrypt -in coder.dat -inkey mykey.pem -out decoder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
OpenFile(1,dossier.s+"decoder.dat")
sortie.s=Space(Lof(1))
ReadData(1,@sortie.s,Lof(1))
CloseFile(1)
DeleteFile(dossier.s+"entrer.dat")
DeleteFile(dossier.s+"decoder.dat")
DeleteFile(dossier.s+"coder.dat")
ProcedureReturn sortie.s
EndProcedure
;-Fin de Procedure RSA:
Procedure send(id,entrer.s,key.s);-Procedure d'envoi de reponse chiffrer
SendNetworkString(id,rc5encrypt(entrer.s,key.s))
EndProcedure
Procedure threadclient(id)
Protected *Buffer=AllocateMemory(1024),commande.s,param.s,hkey.s,user.s,status.l=0,calc.s,total.s,taille.l,security.l=0,ckey.s,skey.s=gen_key(32),start.l=ElapsedMilliseconds()
PrintN("Thread commencer pour le client : "+Str(id)+" "+FormatDate("%hh:%ii:%ss", Date()))
Repeat
If SEvent And ClientID=id;-Test si il y a un evenement reseau, et si cela concerne le client de ce thread...
Select SEvent
Case #PB_NetworkEvent_Data
PrintN("Client : "+Str(id)+" Envoi une commande. "+FormatDate("%hh:%ii:%ss", Date()))
retourrecu:FillMemory(*Buffer,1024):taille=ReceiveNetworkData(id, *Buffer, 1024);-c'est plus rapide de faire un FILLMEMORY qu'un ALLOCATEMEMORY + FREEMEMORY et on peut pas laisser en memoire les commandes précédantes...
total.s+PeekS(*Buffer,taille)
If taille=1024:Goto retourrecu:EndIf;-Si le packet recu est = a la taille maximum definit par packet, alors on a recu q'une partie du packet complet.... on retourne a retourrecu.
If security.l=0:total.s=rsa_openssl_decrypt(total.s,currentdir.s):ElseIf security.l=1:total.s=rc5decrypt(total.s,skey.s):EndIf;-si la connection securiser à été établie alors on dechiffre avec RC5, sinon on dechiffre avec RSA...
commande.s=Mid(total.s,1,4):param.s=Mid(total.s,6):total.s="";-Les commande dans ce programme sont sur 4 octets, ensuite il y a un caractères espace de separation avec les paramètres (optionnel).
PrintN("Client envoi commande : "+commande.s+" "+FormatDate("%hh:%ii:%ss", Date()))
PrintN("Client envoi parametres : "+param.s+" "+FormatDate("%hh:%ii:%ss", Date()))
Select security.l;-Si la connection securiser est établie ou non....
Case 0;-Connection securiser non etablie
Select commande.s
Case "TUNN"
PrintN("Client demande connection securiser. "+FormatDate("%hh:%ii:%ss", Date()))
ckey.s=param.s
security.l=1
send(id,"TOK "+skey.s,ckey.s)
PrintN("Serveur repond : TOK "+skey.s+" "+FormatDate("%hh:%ii:%ss", Date()))
Default;Erreur la commande n'est pas reconnue mauvait certificat ? ou erreur de chiffrement/dechiffrement RSA
CloseNetworkConnection(id):quit=id
EndSelect
Case 1;-Connection securiser etablie
Select status.l;-Status d'identification, 0 = non identifier, 1 = identifier
Case 0;-Identification non effectuer
Select commande.s
Case "USER"
PrintN("Client envoi identifiant : "+param.s+" "+FormatDate("%hh:%ii:%ss", Date()))
If param.s="Jerome"
PrintN("Identifiant valide : "+FormatDate("%hh:%ii:%ss", Date()))
user.s=param.s
hkey.s=gen_key(32)
PrintN("Serveur genere HMACKEY : "+hkey.s+" "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"UOK "+hkey.s,ckey.s)
PrintN("Serveur repond UOK "+hkey.s+" "+FormatDate("%hh:%ii:%ss", Date()))
Else
PrintN("Identifiant incorecte : "+param.s+" "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"UNO",ckey.s)
EndIf
Case "PASS"
PrintN("Client envoi Resultat HMAC : "+param.s+" "+FormatDate("%hh:%ii:%ss", Date()))
If user.s="Jerome"
PrintN("Identifiant valide : "+FormatDate("%hh:%ii:%ss", Date()))
calc.s=hmac_sha1("8be3c943b1609fffbfc51aad666d0a04adf83c9d",hkey.s)
PrintN("Serveur calcul resultat HMAC : "+calc.s+" "+FormatDate("%hh:%ii:%ss", Date()))
If param=calc.s
PrintN("Client : "+Str(id)+" Authentifier. "+FormatDate("%hh:%ii:%ss", Date()))
status.l=1
send(id,"POK",ckey.s)
PrintN("Serveur repond : POK "+FormatDate("%hh:%ii:%ss", Date()))
Else
PrintN("Calcul HMAC ECHEC : "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"PNO",ckey.s)
PrintN("Serveur repond : PNO "+FormatDate("%hh:%ii:%ss", Date()))
EndIf
Else
send(id,"PNO",ckey.s)
EndIf
;CASE "COMMANDE" (sur 4 octets dans cet example)
;....
Case "QUIT"
PrintN("Client demande fin de session. "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"QOK",ckey.s)
PrintN("Serveur repond : QOK "+FormatDate("%hh:%ii:%ss", Date()))
Delay(1000):CloseNetworkConnection(id):quit=id
PrintN("Serveur Ferme connection du client : "+Str(id)+" "+FormatDate("%hh:%ii:%ss", Date()))
Default;-Commande non reconnu...
EndSelect
Case 1;-Identification effectuer
Select commande.s
Case "LOUT"
status.l=0
PrintN("Client demande deconnection "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"LOK",ckey.s)
PrintN("Serveur repond : LOK "+FormatDate("%hh:%ii:%ss", Date()))
;CASE "COMMANDE" (sur 4 octets dans cet example)
;....
Case "QUIT"
PrintN("Client demande fin de session. "+FormatDate("%hh:%ii:%ss", Date()))
send(id,"QOK",ckey.s)
PrintN("Serveur repond : QOK "+FormatDate("%hh:%ii:%ss", Date()))
Delay(100):CloseNetworkConnection(id):quit=id
PrintN("Serveur Ferme connection du client : "+Str(id)+" "+FormatDate("%hh:%ii:%ss", Date()))
EndSelect
EndSelect
EndSelect
EndSelect
start.l=ElapsedMilliseconds()
Else;-Pas d'evenement reseau
If ElapsedMilliseconds()-start.l=>1000*60;-Time out
CloseNetworkConnection(id):PrintN("Client Time Out, Deconnection..."):quit=id
EndIf
Delay(30);-Aucun evenement reseau, on ajoute un timer de 30 mili-seconde pour pas bouffer des ressources processeur...
EndIf;-Fin test evenement reseau
Until quit=id;-boucle evenement reseau
PrintN("Thread terminer "+FormatDate("%hh:%ii:%ss", Date())):Shared quit.l:quit.l=0
EndProcedure;-Fin de threadclient
If Not OpenConsole("Serveur de base securiser"):MessageRequester("Serveur de base securiser","Erreur 1 (OpenConsole)"):End 1:EndIf
EnableGraphicalConsole(1)
PrintN("Serveur de base securiser")
PrintN("Console Initialiser. "+FormatDate("%hh:%ii:%ss", Date()))
If Not OpenCryptRandom():MessageRequester("Serveur de base securiser","Erreur 2 (OpenCryptRandom)"):End 2:EndIf
PrintN("Cryptrandom Initialiser. "+FormatDate("%hh:%ii:%ss", Date()))
If FileSize("mykey.pem")<0:PrintN("CLEF RSA NON EXISTANTE, CREATION EN COUR..."):rsa_openssl_gen(1024,currentdir.s):Else:PrintN("Clef RSA existante."):EndIf
If Not InitNetwork():MessageRequester("Serveur de base securiser","Erreur 3 (INITNETWORK)"):End 3:EndIf
PrintN("Network Initialiser. "+FormatDate("%hh:%ii:%ss", Date()))
If Not CreateNetworkServer(0,24,#PB_Network_TCP,"127.0.0.1"):MessageRequester("Serveur de base securiser","Erreur 5 (CreateNetworkServer)"):End 5:EndIf
PrintN("Serveur operationnel. "+FormatDate("%hh:%ii:%ss", Date()))
start.l=ElapsedMilliseconds()
Repeat;-Boucle principal du programme.
SEvent = NetworkServerEvent();-detecte les evenements reseaux (SEvent est en GLOBAL pour que les thread client puisse le vérifier)
If SEvent;-Si il y a un evenement alors....
ClientID = EventClient();-On récupère le numéro client.
Select SEvent;-Quel type d'evennement...
Case #PB_NetworkEvent_Connect;-Un nouveau client = un nouveau THREAD...
CreateThread(@threadclient(),ClientID)
Case #PB_NetworkEvent_Disconnect;-Un client en moins = un thread en moins....
PrintN("Client : "+Str(ClientID)+" est partie. "+FormatDate("%hh:%ii:%ss", Date()))
quit.l=ClientID.l
EndSelect
Else;-Pas de nouveau evennement...
Delay(30);-Un petit delay pour pas monopoliser les ressources CPU....
EndIf;-Fin du test evennement.
ForEver;-Fin de Boucle principal du programme.
Code : Tout sélectionner
;Base d'un client securiser avec openssl:
;Necessaire : OPENSSL installer dans C:\OPENSSL\BIN
;-Fonctionnement du client :
;-1 Le client initialise la connection securiser, il ne peut faire rien d'autre sans cela.
;-2 Le serveur confirme la connection securiser
;(REMARQUE : La connection sécuriser est initialiser avec du RSA, et ensuite ce poursuit en RC5)
;-3 Le client envoi sont identifiant
;-4 Le serveur confirme l'identifiant et envoi un SALT pour l'opération de validation du mot de passe (HMAC SHA1)
;-5 Le client envoi le resultat de l'opération de validation de sont mot de passe avec le salt (HMAC SHA1)
;-6 Le serveur confirme l'authentification
;-7 Le client peut effectuer des action en tant qu'utilisateur authentifier (içi LOGOUT ou QUIT....)
;-8 Le Serveur repond au demande d'action...
;-9 Le client indique la fin de la session.
;-10 Le serveur confirme, et deconnecte, supprimme le THREAD du client.
;REMARQUE : Si le client tarde à envoyer une commande, le serveur coupe la connection et supprime le THREAD du client (au bout d'une minute dans ce code)
;-Protocole :
;Etablisement de la connection securiser :
;C : TUNN CKEY
;S : TOK SKEY | TNO (TOK = Initialisation de la connection securiser ok, TNO = pas ok et pas implementer..)
;Identification :
;C : USER LOGIN
;S : UOK HMACKEY | UNO (UOK = Identifiant existant, UNO = Identifiant inéxistant)
;C : PASS HMACRESULT
;S : POK | PNO (POK = Mot de passe corecte, PNO = Mot de passe incorecte)
;Deconnection :
;C : LOUT
;S : LOK
;Quitter :
;C : QUIT
;S : QOK
;-Constantes pour RC5:
;crypt provider:
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"
#MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"
#MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider v1.0"
#MS_AES_PROV ="Microsoft AES Cryptographic Provider v1.0"
#MS_RSA_PROV ="Microsoft RSA Signature Cryptographic Provider v1.0"
;Crypt-Constants
#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 24576 ;$6000
#ALG_CLASS_HASH = 32768 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 2048
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8
; Valid hashing algorithms:
;
#ALG_SID_HMAC = 9
#ALG_SID_MAC = 5
#ALG_SID_MD2 = 1
#ALG_SID_SHA = 4
#ALG_SID_SHA1 = 4
#ALG_SID_SSL3SHAMD5 = 8
#ALG_SID_DES = 1
#ALG_SID_3DES = 3
#ALG_SID_3DES_112 = 9
#CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
#CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
#CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
#CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
#CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CALG_DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_DES
#CALG_3DES = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES
#CALG_3DES2 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_3DES_112
;-Fin de Constantes pour RC5
;-debut de variables
Global ClientID.l,SEvent.l, quit.l=0
Global path.s="C:\openssl\bin\"
Global currentdir.s=GetPathPart(ProgramFilename())
;-fin de variables
Procedure.s hextoasc(entrer.s)
For a = 1 To Len(entrer.s) Step 2
sortie.s+Chr(Val("$"+Mid(entrer.s,a,2)))
Next a
ProcedureReturn sortie.s
EndProcedure
Procedure.s hmac_sha1(key.s,msg.s)
If(Len(key.s)>64); Si key est plus grand que 64 octets...
key.s=SHA1Fingerprint(@key.s,Len(key.s))
key.s=hextoasc(key.s)
EndIf
key.s=LSet(key.s,64,Chr(0));Il faut que la clef soit de 64 octets, on ajoute donc autant de fois que necessaire le caractères ASCII 0.
ipad.s=LSet(ipad.s,64,Chr($36));On prépare la variable ipad (64 fois le caractère $36)
opad.s=LSet(opad.s,64,Chr($5c));On prépare la variable opad (64 fois le caractère $5c)
For a=1 To 64
opadt.s+Chr(Asc(Mid(opad,a,1))!Asc(Mid(key,a,1))); on prépare la variable opadt (opad XOR key)
ipadt.s+Chr(Asc(Mid(ipad,a,1))!Asc(Mid(key,a,1))); on prépare la variable ipadt (ipad XOR key)
Next a
ipadt.s+msg.s;on ajoute le message a ipad.
hipad.s=SHA1Fingerprint(@ipadt.s,Len(ipadt.s))
opadt.s+hextoasc(hipad.s)
hopad.s=SHA1Fingerprint(@opadt.s,Len(opadt.s))
ProcedureReturn hopad.s
EndProcedure
Procedure.s rc5encrypt(String$, Key$);-Chiffrement RC5 grce à l'API WINDOWS
Protected *Buffer
Protected DataLength.l
Protected hProv
Protected hHash
Protected result.s
*Buffer = AllocateMemory(Len(String$) * 2 + 64)
DataLength.l = Len(String$)
PokeS(*Buffer, String$)
If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
EndIf
If hProv
CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
If hHash
CryptHashData_(hHash, @Key$, Len(Key$), 0)
CryptDeriveKey_(hProv, #CALG_3DES2, hHash, #CRYPT_EXPORTABLE, @hKey)
If hKey
If CryptEncrypt_(hKey, 0, #True, #Null, *Buffer, @DataLength, Len(String$) * 2 + 64)
EndIf
CryptDestroyKey_(hKey)
EndIf
CryptDestroyHash_(hHash)
EndIf
CryptReleaseContext_(hProv, 0)
EndIf
result.s = Space(DataLength * 3)
Base64Encoder(*Buffer, DataLength, @result, DataLength * 3)
FreeMemory(*Buffer)
ProcedureReturn result
EndProcedure
Procedure.s rc5decrypt(String$, Key$);-DéChiffrement RC5 grce à l'API WINDOWS
Protected *Buffer
Protected DataLength.l
Protected hProv
Protected hHash
Protected result.s
*Buffer = AllocateMemory(Len(String$) * 2 + 64)
DataLength.l = Base64Decoder(@String$, Len(String$), *Buffer, Len(String$) * 2 + 64)
If CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, 0) = 0
CryptAcquireContext_(@hProv, #Null, #MS_ENHANCED_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
EndIf
If hProv
CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
If hHash
CryptHashData_(hHash, @Key$, Len(Key$), 0)
CryptDeriveKey_(hProv, #CALG_3DES2, hHash, #CRYPT_EXPORTABLE, @hKey)
If hKey
If CryptDecrypt_(hKey, 0, #True, 0, *Buffer, @DataLength)
result.s = PeekS(*Buffer, DataLength)
EndIf
CryptDestroyKey_(hKey)
EndIf
CryptDestroyHash_(hHash)
EndIf
CryptReleaseContext_(hProv, 0)
EndIf
FreeMemory(*Buffer)
ProcedureReturn result
EndProcedure
Procedure.s gen_key(taille);-Générateur de string pseudo-aléatoire (Je n'utilise pas toute la table ASCII, car cela pose des problème avec les caractères spéciaux)
Protected a.l,sortie.s
For a=1 To taille
sortie.s+Chr(CryptRandom(110)+33)
Next a
ProcedureReturn sortie.s
EndProcedure
;-Procedure RSA:
Procedure.s rsa_openssl_gen(taille,dossier.s)
RunProgram(path.s+"openssl.exe","rand -out random.bin "+Str(taille),dossier.s,#PB_Program_Wait| #PB_Program_Hide)
RunProgram(path.s+"openssl.exe","genrsa -rand random.bin -out mykey.pem "+Str(taille),dossier.s,#PB_Program_Wait| #PB_Program_Hide)
RunProgram(path.s+"openssl.exe","rsa -in mykey.pem -out mycert.pem -outform PEM -pubout",dossier.s,#PB_Program_Wait| #PB_Program_Hide)
DeleteFile(dossier.s+"random.bin")
EndProcedure
Procedure.s rsa_openssl_encrypt(entrer.s,dossier.s)
OpenFile(1,dossier.s+"entrer.dat")
WriteData(1,@entrer.s,Len(entrer.s))
CloseFile(1)
RunProgram(path.s+"openssl.exe","rsautl -encrypt -in entrer.dat -inkey mycert.pem -pubin -out coder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
RunProgram(path.s+"openssl.exe","base64 -in coder.dat -out base64.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
OpenFile(1,dossier.s+"base64.dat")
sortie.s=Space(Lof(1))
ReadData(1,@sortie.s,Lof(1))
CloseFile(1)
DeleteFile(dossier.s+"entrer.dat")
DeleteFile(dossier.s+"coder.dat")
DeleteFile(dossier.s+"base64.dat")
ProcedureReturn sortie.s
EndProcedure
Procedure.s rsa_openssl_decrypt(entrer.s,dossier.s)
OpenFile(1,dossier.s+"entrer.dat")
WriteData(1,@entrer.s,Len(entrer.s))
CloseFile(1)
RunProgram(path.s+"openssl.exe","base64 -d -in entrer.dat -out coder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
RunProgram(path.s+"openssl.exe","rsautl -decrypt -in coder.dat -inkey mykey.pem -out decoder.dat",dossier.s,#PB_Program_Wait|#PB_Program_Hide)
OpenFile(1,dossier.s+"decoder.dat")
sortie.s=Space(Lof(1))
ReadData(1,@sortie.s,Lof(1))
CloseFile(1)
DeleteFile(dossier.s+"entrer.dat")
DeleteFile(dossier.s+"decoder.dat")
DeleteFile(dossier.s+"coder.dat")
ProcedureReturn sortie.s
EndProcedure
;-Fin de Procedure RSA:
Procedure send(id,entrer.s,key.s);-Procedure d'envoi de reponse chiffrer
SendNetworkString(id,rc5encrypt(entrer.s,key.s))
EndProcedure
If Not InitNetwork():MessageRequester("Client de base securiser","Erreur 1 (INITNETWORK)"):End 1:EndIf
If Not OpenConsole("Client de base securiser"):MessageRequester("Client de base securiser","Erreur 2 (OpenConsole)"):End 2:EndIf
If Not OpenCryptRandom():MessageRequester("Client de base securiser","Erreur 3 (OpenCryptRandom)"):End 3:EndIf
PrintN("Client de base securiser")
Connection=OpenNetworkConnection("127.0.0.1",24)
If Not Connection:MessageRequester("Client de base securiser","Erreur 4 (OpenNetworkConnection)"):End 4:EndIf
*buffer=AllocateMemory(1024):ckey.s=gen_key(32):Delay(1000)
PrintN("Client envoi : TUNN "+ckey.s)
SendNetworkString(Connection,rsa_openssl_encrypt("TUNN "+ckey.s,currentdir.s))
Repeat
CEvent = NetworkClientEvent(Connection):start.l=ElapsedMilliseconds()
If CEvent;-Evenement reseau
Select CEvent
Case #PB_NetworkEvent_Data
retourrecu:FillMemory(*Buffer,1024):taille=ReceiveNetworkData(Connection, *Buffer, 1024)
total.s+PeekS(*Buffer,taille)
If taille=1024:Goto retourrecu:EndIf
total.s=rc5decrypt(total.s,ckey.s)
PrintN("Client recoit reponse. "+FormatDate("%hh:%ii:%ss", Date()))
PrintN("Packet recu : ["+total.s+"]")
reponse.s=Mid(total.s,1,3):param.s=Mid(total.s,5):total.s=""
Select reponse.s
Case "TOK"
PrintN("Serveur envoi clef de connection securiser.")
skey.s=param.s:controle=2
Case "UOK"
PrintN("Identifiant valider par le serveur."):controle=3
hkey.s=param.s
Case "UNO"
PrintN("Identifiant non valider par le serveur."):controle=2
Case "POK"
PrintN("Mot de passe Corecte, Acces authoriser"):controle=1
Case "PNO"
PrintN("Mot de passe incorecte"):send(Connection,"USER "+login.s,skey.s):controle=0:Delay(30)
Case "QOK"
PrintN("Fermeture confirmer"):controle=0
Case "LOK"
PrintN("Déconnection effectuer"):controle=2
EndSelect
Case #PB_NetworkEvent_Disconnect
quit=1
EndSelect
Else;-Pas d'evenement reseau
If controle=2
PrintN("Identifiant :")
retourlogin:login.s=Input():If login.s="":Goto retourlogin:EndIf
controle=0:send(Connection,"USER "+login.s,skey.s)
PrintN("Envoi de la commande : USER "+login.s)
EndIf
If controle=3
PrintN("Mot de passe :")
retourpass:password.s=Input():If password.s="":Goto retourpass:EndIf
password.s=SHA1Fingerprint(@password.s,Len(password.s)):calc.s=hmac_sha1(password.s,hkey.s)
controle=0:send(Connection,"PASS "+calc.s,skey.s)
PrintN("Envoi de la commande : PASS "+calc.s)
EndIf
If controle=1;-Debut Controle
back:
PrintN("Veuillez entrer la commande :")
PrintN("QUIT | LOGOUT")
commande.s=Input()
Select UCase(commande.s)
Case "LOGOUT"
PrintN("Demande de deconnection...")
send(Connection,"LOUT",skey.s)
PrintN("Envoi de la commande : LOUT")
Case "QUIT"
send(Connection,"QUIT",skey.s):controle=0
PrintN("Envoi de la commande : QUIT")
EndSelect
controle=0
EndIf;-Fin de controle
If ElapsedMilliseconds()-start.l=>1000*60
PrintN("Timer ecouler")
start.l=ElapsedMilliseconds()
EndIf
Delay(10)
EndIf;-Fin evenement reseau
Until quit=1
Cordiallement Caussat Jerome.