Créer un système de licence sécurisé
(Désolé de l'endroit, mais vu que je ne dispose pas encore des droits pour la publier à la bonne section :p)
Table des matières
1) Introduction
2) Pré-requis
3) Le fonctionnement de notre système
4) Notre DLL Licence
5) Programme d'ajout de clé
6) Comment utiliser notre DLL dans notre programme à protéger ?
7) Conclusion
1) Introduction
Vous désirez vendre votre bot ? Vous désirez protéger votre bot afin de le distribuer dans un forum ? Alors ce tutoriel est fait pour vous ! Je vais vous apprendre comment créer un système de licence pour son bot afin de le protéger et restreindre l'accès !
2) Pré-requis
Afin de suivre ce tutoriel correctement, vous devez avoir les bases dans l'utilisation des classes et une connaissance dans la sérialisation pourrait être un plus.
Si vous désirez comprendre aisément ce tutoriel, je vous conseille de lire le tutoriel : Sérialisation en .Net de Olivier Delmotte sur Developpez.Net
Je ne vais pas pouvoir tout détailler le code car certaines choses doivent être admises d'autres doivent être connue. Je ne fais donc que vous apprendre le concept ;)
3) Le fonctionnement de notre système
Notre objectif est qu'à chaque ouverture de notre programme, l'utilisateur doit entrer sa clé de licence afin de pouvoir utiliser le programme. Le programme va télécharger un fichier dans votre site web personnel, va vérifier si la clé de licence est présente dans ce fichier et agira en conséquence.
Le problème : Si un malin arrive à trouver l'adresse du fichier ou intercepter la lecture du fichier, il aura toutes les clés de licence à sa disposition ! Imaginez un peu le carnage et la crédibilité que vous aurez !
La solution : Crypter ce fichier ! Tout simplement ! Pour cela nous allons mettre la sécurité au maximum avec deux solutions : la sérialisation binaire, qui va permettre de crypter le fichier qui contiendra les clés qui elles aussi seront cryptés grâce à l'hachage md5.
Pour développer cette solution nous allons créer un projet "Bibliothèque de classes" afin d'en élaborer une DLL à intégrer dans nos programmes que nous allons utiliser ce système. Puis élaborer une application en Windows Forms afin de générer notre fichier crypté.
4) Notre DLL LicenceKeys
Hop on crée un nouveau projet en Bibliothèque de classes nommé Licence avec une nouvelle classe LicenceKeys.cs
Cliquez pour révéler
Cliquez pour masquer
A noter que j'ai déjà inclut tous les futurs "using"
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Net;
namespace Licence
{
public class LicenceKeys
{
}
}
Nous allons créer un attribut qui contiendra toutes les clés. Par convention, celui ci sera en private pour ne pas pouvoir accéder directement.
private string[] _keys;
Puisque nous déclarons un tableau mais qu'il faut absolument savoir sa taille pour l'utiliser, nous allons le définir dans notre constructeur
// int c'est le nombre de clés qu'on va ajouter au fichier
public LicenceKeys(int KeysNumber)
{
_keys = new string[KeysNumber];
}
Puis, pour remplir cet attribut, on va créer une fonction permettant de les ajouter et de les crypter. Mais avant nous devons ajouter une référence dans notre projet : Projet -> Ajouter un référence -> .NET -> System.Security. Sans oublier la directive using : using System.Security.Cryptography;
// Key : la clé à ajouter dans le fichier
// Index : index du tableau à placer la clé
public void AddKey(string Key, int Index)
{
MD5CryptoServiceProvider md5hash = new MD5CryptoServiceProvider();
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(Key);
KeyBytes = md5hash.ComputeHash(KeyBytes);
string buffer = "";
foreach (byte by in KeyBytes)
{
buffer += by.ToString("x2").ToLower();
}
_keys[Index] = buffer;
}
Il nous maintenant pouvoir vérifier si la clé est bien présente dans notre tableau, pour celà une simple fonction booléenne fera l'affaire.
// Key : Lé clé à vérifier
public bool CheckKey(string Key)
{
MD5CryptoServiceProvider md5hash = new MD5CryptoServiceProvider();
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(Key);
KeyBytes = md5hash.ComputeHash(KeyBytes);
string keymd5 = "";
foreach (byte by in KeyBytes)
{
keymd5 += by.ToString("x2").ToLower();
}
foreach (string k in _keys)
{
if (k == keymd5)
return true;
}
return false;
}
Et voilà nous avons notre classe qui permettra d'enregistrer toutes les clés de licence. Il nous manque juste de l'exporter en fichier, c'est la partie la plus marrante ! On va devoir sérialiser notre classe. Pour celà on ajoute le tag [Serializable] sur notre classe, puis on va créer la fonction permettant de la sérialiser :
// Path : Le chemin complet où enregistrer le fichier crypté
// LicenceKeysObject : L'instance de l'objet Licence
public void Serialise(string Path, object LicenceKeysObject)
{
Stream stream = File.Open(Path, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, LicenceKeysObject);
stream.Close();
}
Et évidemment la partie ou on télécharger le fichier sur notre site web :
// URL : Adresse du fichier sur le site web
public static LicenceKeys Deserialize(string URL)
{
try
{
WebClient wc = new WebClient();
wc.DownloadFile(URL, "licence");
wc.Dispose();
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = File.Open("licence", FileMode.Open);
object result = formatter.Deserialize(stream);
stream.Close();
return (LicenceKeys)result;
}
catch (Exception ex)
{
return null;
}
}
Voilà nous avons notre classe pour créer le fichier de clés cryptées !
Cliquez pour révéler
Cliquez pour masquer
Cadeau !
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Net;
namespace Licence
{
[Serializable]
public class LicenceKeys
{
private string[] _keys;
public bool CheckKey(string Key)
{
MD5CryptoServiceProvider md5hash = new MD5CryptoServiceProvider();
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(Key);
KeyBytes = md5hash.ComputeHash(KeyBytes);
string keymd5 = "";
foreach (byte by in KeyBytes)
{
keymd5 += by.ToString("x2").ToLower();
}
foreach (string k in _keys)
{
if (k == keymd5)
return true;
}
return false;
}
public void AddKey(string Key, int Index)
{
MD5CryptoServiceProvider md5hash = new MD5CryptoServiceProvider();
byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(Key);
KeyBytes = md5hash.ComputeHash(KeyBytes);
string buffer = "";
foreach (byte by in KeyBytes)
{
buffer += by.ToString("x2").ToLower();
}
_keys[Index] = buffer;
}
public LicenceKeys(int KeysNumber)
{
_keys = new string[KeysNumber];
}
public void Serialise(string Path, object LicenceKeysObject)
{
Stream stream = File.Open(Path, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, LicenceKeysObject);
stream.Close();
}
public static LicenceKeys Deserialize(string URL)
{
try
{
WebClient wc = new WebClient();
wc.DownloadFile(URL, "licence");
wc.Dispose();
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = File.Open("licence", FileMode.Open);
object result = formatter.Deserialize(stream);
stream.Close();
return (LicenceKeys)result;
}
catch (Exception ex)
{
return null;
}
}
}
}
Voilà nous avons notre jolie DLL prête à être utilisé !
6) Programme d'ajout de clé
Notre programme qui va permettre de créer le fichier crypté sera composé de quelques éléments :
- ListBox keysListBox : Liste de toutes nos clés
- TextBox keyTextBox : Permet d'écrire une clé
- Button keyAddButton : Permet d'ajouter la clé entrée dans la liste
- Button keyDeleteButton : Permet d'effacer la clé sélectionnée dans la liste
- Button saveButton : Sauvegarder le fichier crypté et le fichier personnel
- Button openButton : Ouvre le fichier local
Commencez par dessiner votre formulaire avec ces éléments comme ceci :
Cliquez pour révéler
Cliquez pour masquer
Loading Image
A ce stade, il ne faut surtout pas oublier d'ajouter en référence notre DLL. Plusieurs choix s'offre à vous : vous compilez le projet précédent et copiez la DLL dans votre répertoire du générateur puis vous ajoutez la référence en parcourant ce fichier soit vous avez opté pour la solution intelligente, vous avec une solution avec votre projet DLL et dans cette même solution vous avez crée le projet générateur, par conséquent vous ajoutez la référence à l'aide de l'onglet "Projet".
Notez que dans le premier cas si vous effectuez des modifications au niveau de votre DLL il faudra la copiez à chaque fois dans votre répértoire afin de la tenir à jour.
On va juste pas trop détailler les fonctions basiques, on va juste ajouter ce qui est sélectionné dans la liste avec le bouton prévu à cet effet ou effacer la clé sélectionnée :
private void keyAddButton_Click(object sender, EventArgs e)
{
keysListBox.Items.Add(keyTextBox.Text); // Ajout dans la liste
keyTextBox.Text = ""; // On vide les champs
}
private void keyDeleteButton_Click(object sender, EventArgs e)
{
// On vérifie qu'on a bien une clé sélectionnée
if (keysListBox.SelectedItem != null)
{
keysListBox.Items.Remove(keysListBox.SelectedItem);
}
}
Maintenant on va s'attaquer à la sauvegarde !
Nous allons ouvrir une boîte de dialogue pour demander où on souhaite enregistrer le fichier, puis créer notre classe LicenceKeys afin d'y ajouter nos clés et la sérialiser là où on a demandé.
Après pour pouvoir modifier plus facilement les clés, on fait une copie locale des clés pour les travailler.
A la fin cela nous donne ça :
private void saveButton_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog(); // Dialogue pour savoir ou on veut enregistrer la fichier
if (sfd.ShowDialog() == DialogResult.OK)
{
// On instancie notre classe et on y ajoute toutes nos clés
Licence.LicenceKeys lk = new Licence.LicenceKeys(keysListBox.Items.Count);
for (int i = 0; i < keysListBox.Items.Count; i++)
{
lk.AddKey(keysListBox.Items.ToString(), i);
}
// On sérialise et enregistre le fichier à l'endroit désiré
lk.Serialise(sfd.FileName, lk);
// Copie locale, on sauvegarde dans le même dossier que l'application
StreamWriter sw = new StreamWriter("cles.txt", false);
foreach (string cle in keysListBox.Items)
{
sw.WriteLine(cle);
}
sw.Close();
}
}
Nous voila avec un fichier crypté fraîchement prêt à être utilisé ! Pour cela vous devez le mettre en téléchargement HTPP dans votre site internet ou trouver une solution alternative.
Mainteant pour pouvoir travailler le fichier local, notre bouton va nous ouvrir une boîte de dialogue pour savoir où se trouve notre fichier en copie locale.
private void openButton_Click(object sender, EventArgs e)
{
// Dialogue pour ouvrir le fichier pesonnel des clés saisies
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == DialogResult.OK)
{
StreamReader sr = new StreamReader(ofd.FileName);
string cle = sr.ReadLine();
keysListBox.Items.Add(cle);
while (cle != null)
{
cle = sr.ReadLine();
if(cle != null)
keysListBox.Items.Add(cle);
}
sr.Close();
}
}
6) Comment utiliser notre DLL dans notre programme à protéger ?
Nous avons désormais notre fichier dans notre serveur FTP, un utilitaire pour créer nos clés et notre DLL.
Le problème c'est comment utiliser le système dans notre programme ? Démonstration.
Vous devez créer un formulaire pour demander la clé de l'utilisateur et de la vérifier. Celui ci se compose d'une zone de texte et d'un bouton.
N'oubliez pas d’ajouter la DLL en référence.
On va d'abord désérialiser le fichier, puis utiliser la fonction CheckKey()
private void button1_Click(object sender, EventArgs e)
{
Licence.LicenceKeys lk = Licence.LicenceKeys.Deserialize("ICI L'URL DE VOTRE FICHIER");
// Licence.LicenceKeys lk = Licence.LicenceKeys.Deserialize(@"C:\licence"); <-- Si vous voulez tester sur votre PC
if (lk.CheckKey(textBox1.Text))
{
MessageBox.Show("ok");
}
else
{
MessageBox.Show("nok");
}
}
7) Conclusion
Voilà, c'est fini ! Vous savez désormais la base de ce système. Il ne vous reste qu'à l'améliorer. Voici quelques idées :
- La vérification de la clé peut mettre un certain temps. Utilisez un Thread afin de ne pas estomper l'affichage du formulaire.
- Ajouter un bouton afin de permettre de générer une clé automatiquement dans notre générateur.
- Imposer une structure à la clé (par exemple XXXX-XXXX-X)
Cliquez pour révéler
Cliquez pour masquer