Outils pour utilisateurs

Outils du site


issue84:python_p._53

Table des matières

1

This month, I thought I would create a routine that makes a license key from an email. We all know the reason for having a license key, and if you ever need to have a quick and dirty set of routines to do it, you can use this. Remember, Python is a scripting language, so the source is always readable. There are ways around this; we’ll discuss them in another article. Let’s take a look at the “gross” logic behind the code, before we actually dive into the code.

Ce mois-ci, j'ai pensé créer une routine qui fabrique une clé de licence à partir d'une adresse de courriel. Nous avons tous une raison pour créer une clé de licence, et si vous avez besoin d'avoir rapidement quelques routines vite écrites, vous pouvez utiliser ceci. Rappelez-vous, Python est un langage de script, donc la source est toujours lisible. Il y a des façons de contourner cela ; nous les aborderons dans un autre article. Jetons un coup d’œil à la logique « brute » sous-jacente, avant de nous plonger réellement dans le code.

2

First, we will ask for an email address and then break it into two parts, the local part (the part before the “@” character) and the domain part (the part after the “@” character). There are very specific rules for email address validity, and it can get very complicated. For our purposes, we will only use some of the rules and only on the local part. You can do a web search on the actual rule set. In our code, we will only look at: • lowercase characters • upper case characters • numbers between 0 and 9 • special characters (!#$%&'*+-/=?^_`{|}~.) • period characters are allowed, but may not be repeated next to each other (…, etc)

Tout d'abord, nous allons demander une adresse de courriel, puis la diviser en deux parties, la partie locale (avant le caractère « @ ») et le nom de domaine (après le caractère « @ »). Il existe des règles très précises pour valider une adresse de courriel, et cela devient vite très compliqué. Nous nous contenterons de quelques-unes de ces règles et uniquement sur la partie locale. Vous pouvez chercher l'ensemble des règles sur le web. Dans notre code, nous allons seulement regarder : • minuscules • majuscules • nombres compris entre 0 et 9 • les caractères spéciaux (!#$%&'*+-/=?^_`{|}~.) • les points sont autorisés, mais ne peuvent pas être répétées côte à côte (…, etc)

3

Once we have validated the email, we then will create a “checksum character” which is based on the ascii value of each character in the entire email address, and then divide it by the number of characters in the email address. For example, let’s use a mythical email address of fredjones@someplace.com. If we walk through the email address, we can get the ascii value of each character by using the ord() function. When we add up each of the ascii values, we get a sum of 1670, then we divide that by the length of the email address (23); we get 72. Remember we are using integer division here, so our result will be an integer.

Une fois l'adresse validée, nous allons créer un « caractère somme de contrôle » qui est basé sur la valeur ASCII de chaque caractère de l'adresse complète, puis le diviser par le nombre de caractères de l'adresse. Par exemple, prenons l'adresse factice pierredupont@quelquepart.fr. En parcourant l'adresse, nous pouvons obtenir la valeur ASCII de chaque caractère en utilisant la fonction ord(). En additionnant chacune des valeurs ASCII, on obtient une somme de 2048, que l'on divise par la longueur de l'adresse (27) ; et nous obtenons 75. Nous utilisons la division entière ici, de sorte que notre résultat soit un entier.

4

Now that we have our checksum value, we subtract 68 from that (ascii ‘D’) to create an offset. We use this offset when we encode each character in the email. Just to make things a bit harder to decode, we put the length (with offset) as character position 2 and the checksum as character position 4. So for the email fredjones@someplace.com we get a license key of: j[vHihnsriwDwsqitpegi2gsq Lets get started with the code. Since this is the 53rd article in the series, I won’t be quite as verbose from here on out.

Maintenant que nous avons notre somme de contrôle, on en soustrait 68 (ascii 'D') pour créer un décalage. Nous utilisons ce décalage pour encoder chaque caractère de l'adresse. Pour rendre les choses un peu plus difficiles à décoder, nous mettons la longueur (avec décalage) comme caractère en deuxième position et le caractère somme de contrôle en quatrième position.

Donc, pour l'adresse pierredupont@quelquepart.fr nous obtenons cette clé de licence :

w_pKlyylk|wvu{Gx|lsx|lwhy{5my

Commençons à écrire le code. Puisque c'est le 53e article de la série, je vais commencer à être un peu moins explicite à partir de maintenant.

5

First our imports. import sys Now (as shown above right) we will create a string that will include all of our “legal” characters for the IsValidEmail function. I’ve split it into 3 strings so it fits nicely for the magazine. We combine them in the IsValidEmail routine. We also set a global variable ‘Offset’ to 0. This will be the value that we add (later on) to each character when we create the encoded string.

Tout d'abord les importations.

import sys

Maintenant (ci-dessus à droite), nous allons créer une chaîne qui inclura tous nos caractères « autorisés » pour la fonction AdresseValide. Je l'ai découpée en 3 parties pour qu'elle s'intègre parfaitement dans le magazine. Nous les combinons dans la routine AdresseValide. Nous réglons également une variable globale « decalage » à 0. Ce sera la valeur que nous ajouterons (plus tard) à chaque caractère lorsque nous créerons la chaîne codée.

6

Now for our first function. This (below) is the IsValidEmail routine. Basically we pass the email in the variable s, and an optional debug flag. We use the debug flag, as we have done in the past, to provide some print statements to see how things are going. Usually we would simply pass a 1 as the second parameter if we want to see the progress verbosely. First we assign the passed in email address to the variable ‘email’ and find the ‘@’ character that separates the local from the domain portions of the email. We then assign the local portion of the email to (I think it’s appropriate) ‘local’, and the domain portion to ‘domain’. We then set the boolean isgood flag to False and finally create the ‘localvalid’ string from the 3 shorter strings we set up earlier.

Maintenant, voici notre première fonction. C'est (ci-dessous) la routine AdresseValide. Essentiellement, nous passons l'adresse dans la variable s, et un drapeau optionnel de débogage. Nous utilisons le drapeau de débogage, comme nous l'avons fait dans le passé, pour fournir des instructions d'affichage, afin de voir comment les choses se passent. En général, nous passerons la valeur 1 comme second paramètre si nous voulons afficher la progression.

D'abord, nous affectons l'adresse reçue à la variable « adresse » et cherchons le caractère « @ » qui sépare la partie locale du domaine. Puis, nous affectons la partie locale de l'adresse à (je pense que c'est approprié) « local », et la partie de domaine à « domaine ». Nous réglons ensuite le drapeau booléen « valide » à False et enfin créons la chaîne « localvalid » avec les 3 chaînes plus courtes dont nous avons parlé plus haut.

7

Next (top right) we simply walk through each character in the local portion of the email against the list of valid characters using the in keyword. If any character in the local portion of the email fails the test, we break out of the for loop, setting the ‘isgood’ flag to False. Finally, we look for any set of period characters that are contiguous. We use the string.find routine that will match anything that is like ‘..’ or ‘…’ and so on. Being a lazy programmer, I used only a single “double dot” check that works for anything more. r = email.find(“..”) if r > -1: isgood = False

Ensuite (en haut à droite) nous comparons tout simplement chaque caractère dans la partie locale de l'adresse à la liste de caractères autorisés à l'aide du mot-clé « in ». Si n'importe quel caractère échoue au test, nous sortons de la boucle, en réglons l'option « valide » à False.

Enfin, nous cherchons s'il y a des points qui se suivent. Nous utilisons la routine string.find qui trouvera tout ce qui ressemble à « .. » ou « … » et ainsi de suite. Étant un programmeur paresseux, j'ai utilisé un seul contrôle de « double point » qui fonctionne pour tout le reste.

     r = adresse.find(“..”)      if r > -1:          valide = False

8

The last thing we do in the routine is return the value of the ‘isgood’ flag. return isgood The next routine (bottom right) is the CheckSum routine which is fairly short. We walk each character in the email and create a running sum of the ascii value of each using the built-in ‘ord’ type conversion. As I stated earlier, we take that sum and divide it by the length of the email address. We return the checksum value and the character represented by that checksum.

La dernière chose que fait la routine est de retourner la valeur de l'indicateur « valide ».

     return valide

La prochaine routine (en bas à droite) est la routine de CheckSum qui est assez courte. Nous parcourons chaque caractère de l'adresse et créons la somme des valeurs ASCII de chacun en s'aidant de la fonction ord intégrée qui convertit en nombres. Comme je l'ai dit plus tôt, nous divisons cette somme par la longueur de l'adresse. Nous retournons la somme de contrôle et le caractère correspondant.

9

Now for the EncodeKey routine. While it looks simple, it requires some concentration so pay attention! We assign the Offset variable to global status so we can change it within the function and so it can be used in other functions. We then set the Offset variable to the checksum minus 68. As in the example presented at the beginning of the article, it would be 72-68 which equals 4. We then step through each character of the email address adding the offset to the ascii value of that character. For the ‘f’ in ‘fredjones’, it would be 102 + 4 or 106 which equates to ‘i’. Using the counter variable ‘cntr’, we then determine what we add to the ‘NewEmail’ string we build up character by character. Notice in the code that we go from 0 to the length of the email, so character 0 is ‘f’, character 1 is ‘r’ and so on. Now comes the part that might confuse some of you. If cntr is a value of 1 (‘r’), we insert the character for the length of the email + 68 and then the offset character, which using our example would be iYt. The next time we go through the loop, cntr will equal 2, but we already have 3 characters in the email. That’s where we want to insert the checksum character (‘F’) and then the third character offset. From there, we simply add each offset character to the string, and when the loop is done, we return the key (top right).

Maintenant, la routine EncodeCle. Elle paraît simple, mais elle nécessite une certaine concentration donc faites bien attention ! La variable decalage est mise à l'état « global », pour qu'on puisse la modifier dans la fonction et l'utiliser ensuite dans d'autres fonctions. Nous réglons ensuite la variable decalage à la somme de contrôle moins 68. Pour l'exemple présenté au début de l'article, cela ferait 75-68 donc 7. Nous modifions ensuite chaque caractère de l'adresse en ajoutant le décalage à sa valeur ascii. Pour le « p » de « pierredupont », cela fait 112 + 7 soit 119 ce qui équivaut à « w ». En utilisant la variable « compteur », nous construisons la chaîne « NouvelleAdresse » caractère par caractère. Remarquez dans le code que nous allons de 0 à la longueur de l'adresse, donc le caractère 0 est « p », le caractère 1 est « i » et ainsi de suite. Maintenant vient la partie qui pourrait en perdre quelques-uns parmi vous. Lorsque compteur vaut 1 (« i »), nous insérons le caractère correspondant à la longueur de l'adresse + 68 puis le caractère « décalé », ce qui fait pour notre exemple w_p. La prochaine fois que nous passerons dans la boucle, compteur sera égal à 2, mais nous avons déjà 3 caractères dans l'adresse. C'est là que nous voulons insérer le caractère somme de contrôle (« K ») puis le troisième caractère « décalé ». De là, nous ajoutons simplement chaque caractère « décalé » à la chaîne, et lorsque la boucle est terminée, nous retournons la clé (en haut à droite).

10

The DecodeKey routine (bottom right) basically reverses the process we used in the EncodeKey routine. One thing you might notice here is that in the first ‘if debug’ statement of this function, I used ‘!= 0’ rather than ‘== 1’, simply to remind you that the two can be interchangeable. The DoIt function (below) asks for an email address using ‘raw_input’, then calls the functions in order to create the license key. Lastly, we call the DoIt routine. if name == “main”: DoIt()

La routine DecodeCle (en bas à droite) renverse simplement le processus utilisé dans la routine EncodeCle. Une chose à remarquer ici, c'est que dans la première déclaration « if debug » de cette fonction, j'ai utilisé « != 0 » plutôt que « == 1 », tout simplement pour vous rappeler que les deux sont interchangeables.

La fonction FaisLe (ci-dessous) demande une adresse de courrier électronique en utilisant « raw_input », puis appelle les fonctions afin de créer la clé de licence.

Enfin, nous appelons la routine FaisLe.

if name == “main”:

  FaisLe()

11

Now, obviously the output is not super-encrypted, and if someone were to put in a fair amount of time, they could figure out what we used to create the key fairly easily. However, it should give you enough of a starting point that you could simply modify the code to make it much harder to break. You could, for example, use a random number rather than the ‘D’ (68). If you do that, set a seed in the code so that it will always generate the same random number. You could also go a bit deeper and put the offset value somewhere into the license key, maybe the last character so you could use that as the decryption offset. As always, the full source is available at http://pastebin.com/MH9nVTNK. Until next time, enjoy.

Bon, bien sûr le résultat n'est pas super-crypté et, si quelqu'un voulait y passer pas mal de temps, il pourrait comprendre assez facilement comment nous avons créé la clé. Cependant, cela devrait vous donner un bon point de départ pour que vous puissiez simplement modifier le code pour le rendre beaucoup plus difficile à casser. Vous pourriez, par exemple, utiliser un nombre aléatoire plutôt que le « D » (68). Si vous faites cela, indiquez une « graine » (« seed ») dans le code pour qu'il génère toujours le même nombre aléatoire. Vous pouvez aussi aller un peu plus loin et placer la valeur de decalage quelque part dans la clé de licence, par exemple le dernier caractère, pour pouvoir l'utiliser comme decalage de décryptage.

Comme toujours, la source complète est disponible à http://pastebin.com/ipFm77XJ. En attendant la prochaine fois, amusez-vous bien.

Encadrés orangés

  • page 14 en haut : remplacer simplement Offset par decalage
  • page 14 en bas : remplacer par les lignes 9 à 18 du pastebin traduit
  • page 15 en haut : remplacer par les lignes 19 à 29 du pastebin traduit
  • page 15 au milieu : remplacer par les lignes 35 à 47 du pastebin traduit
  • page 16 en haut : remplacer par les lignes 49 à 66 du pastebin traduit
  • page 16 au milieu : remplacer par les lignes 68 à 84 du pastebin traduit
  • page 16 en bas :remplacer par les lignes 86 à 93 du pastebin traduit
issue84/python_p._53.txt · Dernière modification : 2014/10/20 12:34 de andre_domenech