libtorch 模型加密


pytorch/libtorch qq群: 1041467052

模型部署到現場為了防止泄密,需要加密。加密一方面可以防止泄密,另一方面可以便於模型跟蹤管理,防止混淆。
libtorch的加載模型的函數,torch::jit::load();我點開load可以看到函數。有兩個:

TORCH_API std::shared_ptr<script::Module> load(const std::string& filename,
    c10::optional<c10::Device> device = c10::nullopt);


TORCH_API std::shared_ptr<script::Module> load(std::istream& in,
    c10::optional<c10::Device> device = c10::nullopt);

一般我們都是用上面這個,直接給模型路徑就可以了,下面這個是流,沒用過。然后我試試下面這個流的怎么用。百度了一下istream如何賦值,發現

        std::filebuf in;
        if (!in.open(path_pt, std::ios::in)) {
            std::cout << "fail to open file" << std::endl;
            return 1;
        }

      std::istream ins(&in);

用std::filebuf讀進來,再給istream就可以,然后送到load里面模型可以跑!所以問題就變得簡單了,我只要把流加密保存,讀進來的時候再解密送到load就可以。然而,事情總是不是這么一帆風順的。
所以我就開始嘗試流加密。

#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
int main()
{
    string path_pt = "/data_2/everyday/0622/00000.pt";
    std::filebuf in;
    std::filebuf outbuf;
    outbuf.open("/data_2/everyday/0622/1/0000-en-xor",std::ios::out);
    if (!in.open(path_pt, std::ios::in)) {
        std::cout << "fail to open file" << std::endl;
        return 0;
    }

    FILE *in_file,*out_file;
    in_file=fopen(path_pt.c_str(),"rb");//以讀的方式打開二進制文件
    char ch=fgetc(in_file);

        string key = "1923456789765021";//"A34B123RTAa1qwe3";
        int x = key.size();
        int i = 0;

    //這一斷注釋代碼的功能是對文件的所有位加密,主要用於文本文件。
    while(!feof(in_file))
    {
        ch = ch^key[i>=x?i=0:i++];
        outbuf.sputc(ch);
        ch=fgetc(in_file);
    }
    outbuf.sputc(ch);
    outbuf.close();

}

這里通過異或加密了流並保存在本地。然后把加密的模型讀到工程里面再解密

    string path_pt = "/data_2/everyday/0622/1/0000-en-xor";
    std::filebuf in, outbuf;
    if (!in.open(path_pt, std::ios::in)) {
        std::cout << "fail to open file" << std::endl;
        return 1;
    }

    string key = "1923456789765021";//"A34B123RTAa1qwe3";
    int x = key.size();
    int i = 0;

    do {
        char ch = in.sgetc();
        ch = ch^key[i>=x?i=0:i++];

        outbuf.sputc(ch);
        //        std::cout << (int)ch<<std::endl;
    } while ( in.snextc() != EOF );
    outbuf.sputc(in.sgetc());

    std::istream ins(&outbuf);

可是就是這里出問題了,這樣整然后給libtorch的load函數,爆錯。

Starting /data_2/everyday/0618/build-libtorch-refinenet-unknown-Default/example-app...
terminate called after throwing an instance of 'c10::Error'
  what():  [enforce fail at inline_container.cc:130] . PytorchStreamReader failed checking magic number.
frame #0: c10::ThrowEnforceNotMet(char const*, int, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, void const*) + 0x76 (0x7f3df37c4a76 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libc10.so)
frame #1: torch::jit::PyTorchStreamReader::valid(char const*) + 0x107 (0x7f3e04c7a5c7 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #2: torch::jit::PyTorchStreamReader::PyTorchStreamReader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::istream*) + 0x1ae (0x7f3e04c7b0ce in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #3: torch::jit::load(std::istream&, c10::optional<c10::Device>) + 0x2d1 (0x7f3e08a3fda1 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libtorch.so.1)
frame #4: main + 0x291 (0x456947 in /data_2/everyday/0618/build-libtorch-refinenet-unknown-Default/example-app)
frame #5: __libc_start_main + 0xf0 (0x7f3df0015830 in /lib/x86_64-linux-gnu/libc.so.6)
frame #6: _start + 0x29 (0x44ddd9 in /data_2/everyday/0618/build-libtorch-refinenet-unknown-Default/example-app)

錯誤當然是看不懂,應該就是流不對唄。然后我就取出outbuf一兩個看看:

do {
            char ch = in.sgetc();
            ch = ch^key[i>=x?i=0:i++];

            outbuf.sputc(ch);
            //        std::cout << (int)ch<<std::endl;
        } while ( in.snextc() != EOF );
        outbuf.sputc(in.sgetc());
        //    outbuf.sputc(EOF);
       
            char ch1 = outbuf.sgetc();
            std::cout<<(int)ch1<<std::endl;

            outbuf.snextc();
            ch1 = outbuf.sgetc();
            std::cout<<(int)ch1<<std::endl;

發現打印出來的全是-1.。。。。。咋回事呢?
是不是流你壓到最后指針就在文件的最后,要把指針挪到最前面就可以了呢?然后各種查找資料,這個std::filebuf人家用的比較少,只有個c++官網介紹,http://www.cplusplus.com/reference/fstream/filebuf/。然后,找到了把指針移動到文件頭的函數。

            outbuf.pubseekpos(0,std::ios::in);
            outbuf.pubsync();

可是還是不好使啊!難道函數的問題嗎?

  string path_pt = "/data_2/everyday/0622/1/0000-en-xor";


        //    std::filebuf in,outbuf;

        std::filebuf in, outbuf;
        if (!in.open(path_pt, std::ios::in)) {
            std::cout << "fail to open file" << std::endl;
            return 1;
        }

            long filesize1 = static_cast<long>((in.pubseekoff (0,std::ios::end,std::ios::in)));
           in.pubseekpos(0,std::ios::in); //

           char ch12 = in.sgetc();
           std::cout<<(int)ch12<<std::endl;

            in.snextc();
            ch12 = in.sgetc();
           std::cout<<(int)ch12<<std::endl;

我驗證了直接讀取本地的std::filebuf in可以,filesize1可以記錄大小,當不進行in.pubseekpos(0,std::ios::in);再讀就是-1.說明函數有效的。
然后我又實驗,

string path_pt = "/data_2/everyday/0622/1/0000-en-xor";


        //    std::filebuf in,outbuf;

        std::filebuf in, outbuf;
        if (!in.open(path_pt, std::ios::in)) {
            std::cout << "fail to open file" << std::endl;
            return 1;
        }
        
        outbuf.open("/data_2/everyday/0622/1/0000-jiemi", std::ios::out);

        string key = "1923456789765021";//"A34B123RTAa1qwe3";
        int x = key.size();
        int i = 0;

        do {
            char ch = in.sgetc();
            ch = ch^key[i>=x?i=0:i++];

            outbuf.sputc(ch);
            //        std::cout << (int)ch<<std::endl;
        } while ( in.snextc() != EOF );
        outbuf.sputc(in.sgetc());
         outbuf.close();

我把解密之后的模型保存本地,然后再讀取進來經過:
std::istream ins(&in);
std::shared_ptrtorch::jit::script::Module m_model = torch::jit::load(ins);
這兩步是可以的!!!!!可是問題出現在哪里呢?主要問題在於直接解密的時候:
outbuf.snextc();
ch1 = outbuf.sgetc();
std::cout<<(int)ch1<<std::endl;
這里輸出死活都是-1,。不知道為啥。。。
然后還有一個檢查方法,就是std::istream ins(&in); 檢測ins里面的東西。

 std::istream ins(&in);


 vector<char> v_ch;
 char ch_tmp[1];
 int cnt_ = 0;
 while (ins.read(ch_tmp, 1))
  {
      cnt_ ++;
    v_ch.push_back(ch_tmp[0]);
     std::cout<<(int)ch_tmp[0] <<std::endl;
 }
 while(1);

正常可以推理的時候v_ch里面有2千萬的數據,而直接在線解密的時候是0!。。折騰了好久無解,總感覺哪里還差一步就可以解決這個問題,也重定向了,無解。。。。

然后找來jiaming,他百度用了其他方法實驗,反正只要把流塞到std::istream ins(&in);這里就可以了。

                char* buf = nullptr;
                string path_pt = "/data_2/everyday/0623/nice/jiami2";
                string key = "QO1##gX@@3";

                FILE* file = fopen(path_pt.c_str(), "r");
                fseek(file, 0, SEEK_END);
                unsigned size = ftell(file);
                fseek(file, 0, SEEK_SET);
                buf = (char*)malloc(size);
                memset(buf,0,size);
                unsigned int i=0,j=0;
                while(!feof(file))
                {
                    char ch = (fgetc(file))^(key[i>=key.length()?i=0:i++]);
                    buf[j++]=ch;
                }

                strstreambuf sbuf(buf, sizeof(buf));
//                free(buf);
//                buf = nullptr;
                std::istream ins(&sbuf);

這樣子報錯:

terminate called after throwing an instance of 'c10::Error'
  what():  [enforce fail at inline_container.cc:127] . PytorchStreamReader failed reading zip archive: not a ZIP archive
frame #0: c10::ThrowEnforceNotMet(char const*, int, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, void const*) + 0x76 (0x7f362057fa76 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libc10.so)
frame #1: torch::jit::PyTorchStreamReader::valid(char const*) + 0xa6 (0x7f3631a35566 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #2: torch::jit::PyTorchStreamReader::PyTorchStreamReader(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::istream*) + 0x1fb (0x7f3631a3611b in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #3: torch::jit::load(std::istream&, c10::optional<c10::Device>) + 0x2d1 (0x7f36357fada1 in /data_1/Yang/project/2019/chejian/3rdparty/libtorch/lib/libtorch.so.1)
frame #4: main + 0x296 (0x45665c in /data_2/everyday/0618/build-libtorch-refinenet-unknown-Default/example-app)
frame #5: __libc_start_main + 0xf0 (0x7f361cdd0830 in /lib/x86_64-linux-gnu/libc.so.6)
frame #6: _start + 0x29 (0x44dae9 in /data_2/everyday/0618/build-libtorch-refinenet-unknown-Default/example-app)

然后,他說你把正常的和這個不正常的二進制流打印出來比較就是了。接在上面函數之后這么寫的:

             char* buf = nullptr;
                string path_pt = "/data_2/everyday/0623/nice/jiami2";
                string key = "QO1##gX@@3";

                FILE* file = fopen(path_pt.c_str(), "r");
                fseek(file, 0, SEEK_END);
                unsigned size = ftell(file);
                fseek(file, 0, SEEK_SET);
                buf = (char*)malloc(size);
                memset(buf,0,size);
                unsigned int i=0,j=0;
                while(!feof(file))
                {
                    char ch = (fgetc(file))^(key[i>=key.length()?i=0:i++]);
                    buf[j++]=ch;
                }

                strstreambuf sbuf(buf, sizeof(buf));
               std::istream ins(&sbuf);
                vector<char> v_ch;
                char ch_tmp[1];
                while (ins.read(ch_tmp, 1))
                {
                    v_ch.push_back(ch_tmp[0]);
                    std::cout<<(int)ch_tmp[0] <<std::endl;
                }
               while(1);

發現v_ch只要8位!!!為啥???前幾位的文件流char如下:
80
75
3
4
0
0
8
8
0
0
59
124
-51
80
0
如果說遇到0就算截止,可是前8個本身就有0啊為啥不在之前截止。。無解。
可能是sizeof的問題,然后改成如下:

 char* buf = nullptr;
                string path_pt = "/data_2/everyday/0623/nice/jiami2";
                string key = "QO1##gX@@3";

                FILE* file = fopen(path_pt.c_str(), "r");
                fseek(file, 0, SEEK_END);
                unsigned size = ftell(file);
                fseek(file, 0, SEEK_SET);
                buf = (char*)malloc(size);
                memset(buf,0,size);
                unsigned int i=0,j=0;
                while(!feof(file))
                {
                    char ch = (fgetc(file))^(key[i>=key.length()?i=0:i++]);
                    buf[j++]=ch;
                }

                strstreambuf sbuf(buf, j);
               std::istream ins(&sbuf);
                vector<char> v_ch;
                char ch_tmp[1];
                while (ins.read(ch_tmp, 1))
                {
                    v_ch.push_back(ch_tmp[0]);
                    std::cout<<(int)ch_tmp[0] <<std::endl;
                }
               while(1);

這回v_ch也有2千萬的數據了,大小也是一樣的,可以torch還是報錯!!!然后jiamin說比較輸出來的哪里不一樣。因為cout打印終端,但是可以直接運行可執行文件讓把輸出的內容保存在本地。比如我這個工程構建會生成example的可執行文件。
然后,直接運行可執行文件:

./example &> 1.txt

就可以把打印的內容直接保存在文本。
這樣,正常的和不正常的都保存,然后比較兩個文本,發現不正常的最后比正常的多了一個數字。然后我把上面的代碼改成:
strstreambuf sbuf(buf, j-1);
就可以了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
這個小功能花費了一天半的時間,其實我一開始的半天就搞通可以流讀到load里面,然后都是在解決上面的問題,std::filebuf的那個問題還不知道哪里有問題!

==============================================================================================
下面給出加密的代碼:

#include <iostream>
#include <fstream>
#include<memory.h>

void ShowUsage()
{
    std::cout << "Usage for encryption" << std::endl;
    std::cout << "path_pt" << std::endl;
    std::cout << "path_save_encryption" << std::endl;
    //    std::cout << "length" << std::endl;
    std::cout << "example:\n ./encryption /data_2/small.pt /data_2/small_en" << std::endl;
    return;
}

std::string rand_str(const int len)
{
    srand( (unsigned)time( NULL ) );
    std::string str;
    char symbol[20] = {'!','@','#','$','%','^','&','*','(',')','?','.','<','>','~','-','+','{',']','['};
    int i;
    char ch;
    for(i=0;i<len;++i)
    {
        switch((rand()%4))
        {
        case 1:
            ch='A'+rand()%26;
            break;
        case 2:
            ch='a'+rand()%26;
            break;
        case 3:
            ch=symbol[rand()%20];
            break;
        default:
            ch='0'+rand()%10;
            break;
        }
        str += ch;
    }

    return str;
}



int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        ShowUsage();
        return -1;
    }

    std::string str_len = "16";
    std::string path_pt = argv[1];
    std::string path_save_jiami = argv[2];
    if(argc >= 4)
    {
        str_len = argv[3];
    }

    //    std::string path_pt = "/data_2/everyday/0622/00000.pt";
    //    std::string path_save_jiami = "/data_2/everyday/0623/nice/jiami2";
    //    std::string str_len = "10";

    int len = std::stoi(str_len);
    std::string key = rand_str(len);

    std::filebuf in;
    std::filebuf outbuf;
    outbuf.open(path_save_jiami,std::ios::out);
    if (!in.open(path_pt, std::ios::in)) {
        std::cout << "fail to open model pt" << std::endl;
        std::cout << "please check path: " << path_pt << std::endl;
        return 0;
    }

    FILE *in_file;
    in_file=fopen(path_pt.c_str(),"rb");//以讀的方式打開二進制文件
    char ch=fgetc(in_file);

    int i = 0;
    while(!feof(in_file))
    {
        ch = ch^key[i>=key.size()?i=0:i++];
        outbuf.sputc(ch);
        ch=fgetc(in_file);
    }
    outbuf.sputc(ch);
    outbuf.close();

    std::cout<<"\nsuccess crerate encryption model!" << std::endl;
    std::cout<<"key=\n"<< key << std::endl;

    return 0;
}

解密的話上面零零散散的也有。

轉載:https://www.cnblogs.com/573734817pc/p/11088858.html
python3利用cryptography 進行加密和解密
我們的日常工作中,一定會遇到需要加密的數據,比如:密碼、私密信息... ...

我們不僅要對他們進行加密,更需要對他們進行解密,因為畢竟我們的用戶應該不會看得懂加密過后的字符串吧!!!

在python強大的第三方插件庫中,就有這么一個插件,很好的解決了我們的問題,這個插件的名為:cryptography

cryptography: 的目標是成為“人類易於使用的密碼學包cryptography for humans”,就像 requests 是“人類易於使用的 HTTP 庫HTTP for Humans”一樣。這個想法使你能夠創建簡單安全、易於使用的加密方案。

cryptography安裝。

如果你使用的 Python 版本是 3.5及以上, 你可以使用 pip 安裝,如下:

  pip install cryptography

cryptography加密。

我們使用 Fernet 對稱加密算法,它保證了你加密的任何信息在不知道密碼的情況下不能被篡改或讀取。Fernet 還通過 MultiFernet 支持密鑰輪換。

下面讓我們看一個簡單的例子:

from cryptography.fernet import Fernet
#生成秘鑰cipher_key
cipher_key = Fernet.generate_key()
print(cipher_key)
cipher = Fernet(cipher_key)
text = b'My name is PanChao.'
#進行加密
encrypted_text = cipher.encrypt(text)
print(encrypted_text)
#進行解密
decrypted_text = cipher.decrypt(encrypted_text)
print(decrypted_text)

我們可以看到運行上面代碼結果為:

首先我們需要導入 Fernet,然后生成一個密鑰。我們輸出密鑰看看它是什么樣兒。如你所見,它是一個隨機的字節串。如果你願意的話,可以試着多運行 generate_key 方法幾次,生成的密鑰會是不同的。然后我們使用這個密鑰生成 Fernet 密碼實例。

現在我們有了用來加密和解密消息的密碼。下一步是創建一個需要加密的消息,然后使用 encrypt 方法對它加密。我打印出加密的文本,然后你可以看到你再也讀不懂它了。為了解密出我們的秘密消息,我們只需調用 decrypt 方法,並傳入加密的文本作為參數。結果就是我們得到了消息字節串形式的純文本。

以上淺顯地介紹了cryptography 包的使用。不過這也確實給了你一個關於如何加密解密字符串的簡述。請務必閱讀文檔,做做實驗,看看還能做些什么!

下面附帶一個des對稱加密的python實現方法:

from pyDes import des, CBC, PAD_PKCS5
import binascii

# 秘鑰
KEY = 'mHAxsLYz'

def des_encrypt(s):
    """
    DES 加密
    :param s: 原始字符串
    :return: 加密后字符串,16進制
    """
    secret_key = KEY
    iv = secret_key
    k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
    en = k.encrypt(s, padmode=PAD_PKCS5)
    return binascii.b2a_hex(en)

def des_descrypt(s):
    """
    DES 解密
    :param s: 加密后的字符串,16進制
    :return:  解密后的字符串
    """
    secret_key = KEY
    iv = secret_key
    k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
    de = k.decrypt(binascii.a2b_hex(s), padmode=PAD_PKCS5)
    return de

test = des_encrypt("panchao")
print(test)
print(des_descrypt(test))

小弟不才,同時謝謝友情贊助


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM