Lors de l'élaboration de contrats, je pense qu'il y a des situations où vous devez livrer les livrables au client. Dans un tel cas, par exemple, si la fonction peut être fournie en SaaS, le côté client appuiera sur l'API et utilisera la fonction, il ne sera donc bien sûr pas possible de saisir le code source de ce côté. Cependant, je pense que dans de nombreuses situations, ce n'est pas réaliste. Il existe une bibliothèque appelée PyArmor qui est utile dans de tels cas. PyArmor est une bibliothèque qui crypte le code source et, en théorie, le code source ne peut pas être restauré. C'est une bibliothèque très pratique lorsque vous souhaitez livrer rapidement le code source. Outre le simple chiffrement, il est également possible de chiffrer après l'octroi de diverses licences (période d'utilisation, dispositif d'exécution, etc.). Concernant PyArmor, d'autres articles sortiront si vous google, mais comme les spécifications ont légèrement changé, j'ai essayé de le résumer sous forme d'article cette fois en incluant la signification du mémo. Pour savoir comment utiliser PyArmor, reportez-vous au document officiel ci-dessous.
Le code source de ce blog est publié sur [GitHub]. Veuillez vous référer à l'environnement local de Mac pour l'environnement et Pipfile pour les bibliothèques requises.
Voici le code avant le cryptage. [Single_Module] Après lecture du fichier image, le modèle VGG16 entraîné est utilisé pour la classification et l'affichage des images.
Single_Module/main.py
import os
import sys
import cv2
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision import models, transforms
sys.path.append(os.path.abspath('..'))
import imagenet_class
img = cv2.imread('../baseball.png')
img = cv2.resize(img, (256, 256))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_tensor = transforms.ToTensor()(img)
img_tensor = img_tensor.unsqueeze_(0)
model = models.vgg16(pretrained=True)
output = model(img_tensor)
output = np.argmax(output.detach().numpy())
print(imagenet_class.target[str(output)][1]) # ballplayer
plt.imshow(img)
plt.show()
Vous pouvez voir que le résultat est également correctement classé comme «joueur de balle».
Cryptez avec la commande suivante.
$ pyarmor obfuscate main.py
Après l'exécution, le répertoire dist
sera créé directement en dessous. Le contenu du fichier est le suivant.
Comme vous pouvez le voir dans la section Génération de licence pour les scripts obfusqués
de la documentation officielle, exécutez d'abord la commande suivante: (Nom librement tel que r001)
$ pyarmor licenses --expired 2022-01-01 r001
Ensuite, le répertoire licenses
sera créé directement en dessous, et divers fichiers seront créés en dessous. Ensuite, comme précédemment, le fichier principal est chiffré avec la commande pyarmor obfuscate
, mais il est exécuté avec les options suivantes.
$ pyarmor obfuscate --with-license licenses/r001/license.lic main.py
Ensuite, il est possible de crypter sous la forme d'une licence avec une date d'expiration. [Single_Module_Obfuscating_pre]
--expired 2019-01-01
avec la commande précédente, vous ne pourrez pas exécuter le fichier principal chiffré car il a déjà expiré.
――Il est également possible d'émettre une licence qui spécifie l'appareil de la même manière que ci-dessus. Veuillez consulter le document officiel pour plus de détails.Le fichier principal chiffré peut être exécuté comme un script python normal. Le fichier principal chiffré jusqu'à présent existe directement sous le répertoire dist
, donc le chemin relatif est légèrement différent de l'original. Par conséquent, afin d'aligner les chemins, j'ai fait une configuration comme [Single_Module_Obfuscating]. Je n'ai rien fait d'autre que de changer l'emplacement des fichiers. Essayez d'exécuter la commande suivante.
$ python main.py
【résultat】
[out] ballplayer
Vous pouvez voir que le résultat est exactement le même qu'avant le chiffrement. Essayons également de voir à quoi ressemble le fichier principal essentiel.
$ cat main.py
from pytransform import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'\x50\x59\x41\x52 ...(Omis ci-dessous)
Vous pouvez voir qu'il est normalement crypté de cette manière. Comme je l'ai mentionné plus tôt, la bibliothèque dynamique générée en même temps est toujours requise pour que ce fichier principal soit exécuté.
Par défaut, tous les fichiers .py
situés directement en dessous sont chiffrés. Si vous souhaitez crypter récursivement tous les fichiers .py
, y compris les sous-répertoires, exécutez avec les options suivantes.
$ pyarmor obfuscate --recursive main.py
Je vais essayer.
[Whole_Module] est le code source avant le chiffrement, mais c'est le même qu'avant. (Séparez simplement les fichiers)
Le main.py
directement en dessous lit le model / model.py
sous la sous-direction.
Whole_Module/model/model.py
from torch import nn
from torchvision import models
class SampleModel(nn.Module):
def __init__(self):
super(SampleModel, self).__init__()
self.backborn = models.vgg16(pretrained=True)
def forward(self, x):
x = self.backborn(x)
return x
Whole_Module/main.py
import os
import sys
import cv2
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision import transforms
from model.model import SampleModel
sys.path.append(os.path.abspath('..'))
import imagenet_class
img = cv2.imread('../baseball.png')
img = cv2.resize(img, (256, 256))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_tensor = transforms.ToTensor()(img)
img_tensor = img_tensor.unsqueeze_(0)
model = SampleModel()
output = model(img_tensor)
output = np.argmax(output.detach().numpy())
print(imagenet_class.target[str(output)][1])
plt.imshow(img)
plt.show()
Maintenant, lorsque vous exécutez la commande précédente, un nouveau répertoire dist
sera créé et la bibliothèque chiffrée main.py
, model.py
et dynamique sera créée. [Whole_Module_Obfuscating_pre]. Cependant, comme il ne peut pas être exécuté pour la même raison qu'avant (le chemin relatif du fichier image est différent), le fichier généré a été déplacé. Cela peut également être exécuté sans aucun problème comme auparavant. [Whole_Module_Obfuscating]
Recommended Posts