Voilà la mise à jour "Python 3" des codes du tuto concerné:
http://python.jpvweb.com/mesrecettes...masque_jetable
le fichier de bibliothèque "bibcrypto_bbs.py" est en pièce jointe.
Il y a quelques différences évidentes (xrange => range, print ... => print(...), ...), plus une qui ne l'est pas: les fonctions de cryptage/décryptage travaillent sur des bytes et non des str! Cela nécessite des conversions dans les 2 sens avec connaissance de l'encodage si ce n'est pas de l'ascii pur.
Attention:
pour les explications, voir le tuto: je ne vais pas le réécrire ici!
Je rappelle simplement que, au lieu d'utiliser une liste de codes pour le cryptage, on utilise ici un algorithme qui fabrique une liste de codes au hasard aussi grande qu'on le veut, afin de crypter n'importe quoi (texte, image, vidéo, etc...). Il faut, bien entendu que pour décrypter, on dispose du même algorithme et des 2 nombres qui ont servi au cryptage.
Pour l'utilisation: En principe, on écrit du code Python dans un autre fichier qu'on place dans le même répertoire, et qui commence par importer les fonctions nécessaires avec:
from bibcrypto_bbs import genpremier_bbs, gengraine_bbs, crypte_bbs, chainemultilignes, entiermultilignes
Mais, bien sûr, si on écrit à la fin du fichier "bibcrypto_bbs.py", cette ligne d'importation ne doit pas être utilisée!
Génération des nombres nécessaires au fonctionnement du générateur Blum Blum Shub:
1 2 3 4 5 6
| np1 = genpremier_bbs(1024, 100) # 1er nb premier de 1024 bits congru à 3 modulo 4 (avec 100 essais pour MillerRabin)
np2 = genpremier_bbs(1024, 100) # 2e nb premier ... (idem) ...
pnp = np1*np2 # produit des 2 nombres premiers précédents
graine = gengraine_bbs(pnp, g1=10000000, g2=99999999) # graine à 8 chiffres, premier avec pnp
print("pnp =", pnp)
print("graine =", graine) |
Le résultat est bien sûr différent à chaque fois (heureusement!), par exemple:
1 2
| pnp = 14918821236690364048803357697827915330938033283968520044694771536930083962204522731085107976364842849618124584872512005469561358619582153354051962019051713882879895713608416554642100450496860545667414057413718678420906387634010424980338817514953869099955818435893555577287077984236763950252884280914769585067833911665408393977438690278779688153345857590291910776611048398078671383442699683071755220406286503400148046259020107019158117755289706301669627923537440322481447108082279600092947909584337555856165935214929894504908491221907537540009691905645323823752752168789754791148160238231187156550548453091395261440381
graine = 99380446 |
Vous noterez qu'on obtient un nombre de plus de 600 chiffres (2048 bits) de cette façon, et ceci en moins d'une minute. Un nombre de cette taille est quasi impossible à factoriser actuellement (en attendant l'ordinateur quantique?).
A noter que grâce à la fonction "entiermultilignes", on peut intégrer ce grand entier dans un source Python comme suit:
print(entiermultilignes(pnp, nvar='pnp', nbcar=78, fdl='\n'))
Ce qui donnera:
1 2 3 4 5 6 7 8 9 10
| pnp = "1491882123669036404880335769782791533093803328396852004469477153693008\
39622045227310851079763648428496181245848725120054695613586195821533540519620\
19051713882879895713608416554642100450496860545667414057413718678420906387634\
01042498033881751495386909995581843589355557728707798423676395025288428091476\
95850678339116654083939774386902787796881533458575902919107766110483980786713\
83442699683071755220406286503400148046259020107019158117755289706301669627923\
53744032248144710808227960009294790958433755585616593521492989450490849122190\
75375400096919056453238237527521687897547911481602382311871565505484530913952\
61440381"
pnp = int(pnp) |
On va maintenant crypter et décrypter le texte suivant:
1 2 3 4 5 6 7 8 9 10
| msg = """Article premier - Les hommes naissent et demeurent libres et égaux en droits. Les distinctions sociales ne peuvent être fondées que sur l'utilité commune.
Article II - Le but de toute association politique est la conservation des droits naturels et imprescriptibles de l'homme. Ces droits sont la liberté, la propriété, la sûreté, et la résistance à l'oppression.
Article III - Le principe de toute souveraineté réside essentiellement dans la nation. Nul corps, nul individu ne peut exercer d'autorité qui n'en émane expressément.
Article IV - La liberté consiste à faire tout ce qui ne nuit pas à autrui: ainsi l'exercice des droits naturels de chaque homme n'a de bornes que celles qui assurent aux autres membres de la société la jouissance de ces mêmes droits. Ces bornes ne peuvent être déterminées que par la loi.
Article V - La loi n'a le droit de défendre que les actions nuisibles à la société. Tout ce qui n'est pas défendu par la loi ne peut être empêché, et nul ne peut être contraint à faire ce qu'elle n'ordonne pas.
""" |
Il s'agit d'un extrait de la déclaration des droits de l'homme: ce n'est pas inutile de le relire de temps en temps...
On considèrera qu'il est écrit avec un encodage "utf-8": c'est important à cause des caractères accentués!
Et voilà le cryptage/décryptage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # conversion des str en bytes
msgb = bytes(msg, 'utf-8')
# cryptage (msgb et chb sont de type bytes)
chb = crypte_bbs(msgb, graine, pnp)
# décryptage (chb et msgb2 sont de type bytes)
msgb2 = crypte_bbs(chb, graine, pnp)
# conversion des bytes en str
msg2 = str(msgb2, 'utf-8')
# affichage
print(msg2) |
On utilise la même fonction pour crypter et décrypter et c'est normal puisqu'on fait un "xor" entre le byte du texte et le byte du code: 2 applications successives redonne le résultat initial.
On obtient bien, après décryptage, le même message qu'au début!
Si on veut transmettre la version cryptée à quelqu'un par email, on peut la mettre dans un fichier (écriture binaire "wb") et la mettre en pièce jointe. On peut aussi la transformer en texte imprimable avec base64 en utilisant la fonction "chainemultilignes" de cette façon:
1 2 3 4 5
| import base64
chb64 = base64.b64encode(chb)
print(chainemultilignes(str(chb64, 'ascii'))) |
Ce qui affiche:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ch = "RXJ0vi51uZgFCmbABi/95jcbg3oXC3R5dBaL0ycU1pbL2DiIEmXsfLeRT647Wow2pBQ9Ide\
wvbTHZvR0cQVIwMocn1omwFr0c8ZshPzNEIYPmEzEE1FmDitsNB0NFQiK/edxs+/QZA5drtofrEAA\
b0Hh+FNvbPSuXmUlwWzcT5f2GXve/LRxWVAZrb7rhGZjIK3ByPcsNI/4CpelVEGJv6XV8aiwZj4wK\
xXliuPfK4hoitlckGA5DobWgVR6Nil+X7Xb5berZoJoovPpf06XJws61smMnan8TlQQSldtCVxw38\
WgMyKI8QDjW5AeETvBkqZwX0fI27/aSEHcavKy7O8CrasmZONNtW+rTEdGxIzdjoEW1dlAnF8/jA3\
humu4tTbRZWMnlV5mJa6fgeDQcE5DqFUXJ3fGwPJBP3WMX4yLjuxzrS1yM5al0BvQnXxP7K5WbeDk\
9XAA5IwIE5egZbr8Iy8aX6UPYrE4jT92FSS8fR28yrB7sU8yzLlcgIIn5ghO0VGm0SgURU7D0Lj8+\
5yiRUrIJWlHon4aVTGqQNx5y+Eqs7nt4qysZzmUxYl5GniU2BzDBgcncuThacuVtNtfRx8nCkzoBv\
+A6m83Apk976/9Bv3aOZGix5KK27bhCT4JF9Q3fGpl46hiCTDHOWYy8G7eLM5sHIK9m6zwgqBMKeu\
lAqSF3ahRTYS/TAZcnJPrkU/jABU3SjUPrIAz+/S4SlhgrzArEV5cFii/wWbWAO1r6JQUBSH1Hbb3\
faqxWSpI8y0EqJwLD9TsfiuNgnK/LpDRQB9NlsWu4Z16FTj3UUvPPbLO0rsmdhHbt6yyiynOAhfB/\
7ZJZCvGRLglISLzdRrhh9yamBFrSDmwxJrNFHs/LyXLSs3EYDKO91z3gdyZxoOIrhblsZ/hqXqcND\
Kz1/17Yb8z952FRKoOAm7A93yTyBaVotcSBM7e0MxH61ftgqihlD9VFgPrzb7z/gkir6sOEdbJfaA\
/vCJhIssCwt40wN/oIDHrH2poyKKQoVGra6NCJMEHEkVainnjJ1Dqd3xmp/wPf/mvHhHK3JRquc+q\
IgfGLYdP8oHCY9mMJrjrUWeBliCzYabd9O2YZDTvalCWWgajfMxchVpripBaV5OmClWr8whqY6RWN\
4tBJAjNzqmInbAaXkK/UImPUCx5rtEJL7uHcAwNYAeYtPuE6sDbH3u+l9Uv4TJa4q8ZB4xpfAzf3T\
gLsBmZpLGA9V95McBqss2cYF8avWCwt0h8EdDA9vFhrvhPn3AZ32GspN3cRPitLC6o1Unisftt4ur\
biQyYdSzP8a1irLrn9HA3rokQZhYVpuJDHRi9P4jQNITOcfDFMNA8wPx4k43zUhF29xYrUKcL8DVi\
ZaDp9Yg+XTkzAULLRwJIPi4kshzgLt4csahNKHToIKa5tg4=" |
On peut constater qu'on obtient bien la même chose que dans le tuto avec la version Python 2.
Et, bien sûr, celui qui recevra ce message pourra le décoder à condition d'avoir:
- les 2 mêmes nombres (pnp et graine) que ceux qui ont servi au cryptage
- le même programme qui va redonner la même série de nombres au hasard avec les mêmes nombres précédents
décodage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # on fait la conversion de str en bytes
chb64 = bytes(ch, 'ascii')
# on retrouve le texte crypté (chb2 est de type bytes)
chb2 = base64.b64decode(chb64)
# on rappelle les 2 nb nécessaire à BBS
pnp = 14918821236690364048803357697827915330938033283968520044694771536930083962204522731085107976364842849618124584872512005469561358619582153354051962019051713882879895713608416554642100450496860545667414057413718678420906387634010424980338817514953869099955818435893555577287077984236763950252884280914769585067833911665408393977438690278779688153345857590291910776611048398078671383442699683071755220406286503400148046259020107019158117755289706301669627923537440322481447108082279600092947909584337555856165935214929894504908491221907537540009691905645323823752752168789754791148160238231187156550548453091395261440381
graine = 99380446
# on décrypte (chb et msgb2 sont de type bytes)
msgb2 = crypte_bbs(chb2, graine, pnp)
# on convertit de bytes en str pour retrouver le message initial
msg2 = str(msgb2, 'utf-8')
print(msg2) |
msg2 est bien identique au texte initial msg!
Tout cela est donné gratuitement pour rendre service, mais sans garantie, bien entendu!
Amusez-vous bien!
Partager