├── .gitignore ├── test.cpp ├── LICENSE ├── findbase.py ├── README_cn.md ├── basen.h ├── README.md └── mk1f.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | 3 | *.key 4 | *.bin 5 | keys/ 6 | 7 | # executable 8 | *.exe 9 | *.out 10 | 11 | archive/ 12 | */temp/ 13 | tempCodeRunnerFile.* 14 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include "mk1f.hpp" 2 | 3 | int main() { 4 | using namespace Mk1f; 5 | int n = 10; 6 | 7 | char* fs[] = { 8 | "archive/0.7z", 9 | "archive/1.7z", 10 | "archive/2.7z", 11 | "archive/3.7z", 12 | "archive/4.7z", 13 | "archive/5.7z", 14 | "archive/6.7z", 15 | "archive/7.7z", 16 | "archive/8.7z", 17 | "archive/9.7z"}; 18 | 19 | int flg_enc = 1; 20 | if (flg_enc) { 21 | Keys* p = new Keys(n); 22 | p->read("archive/rd.key"); 23 | p->release(); 24 | printf("save keys: %d\n", p->save_keys()); 25 | printf("Keys.encrypt: %d\n", p->encrypt(fs, "archive/kbig.bin")); 26 | 27 | Keys* p2 = p->clone(6); 28 | printf("Keys.decrypt %d: %d\n", 5, p2->decrypt(5, "archive/kbig.bin", "archive/05.7z")); 29 | } else { 30 | printf("encrypt: %d\n", encrypt(n, 64, fs, "archive/big.bin")); 31 | printf("decrypt %d: %d\n", 8, decrypt("keys/8.key", "archive/big.bin", "archive/08.7z")); 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Elaina 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /findbase.py: -------------------------------------------------------------------------------- 1 | def basesize(x: int, maxlen: int = 8, unbase: bool = False, full: bool = False) -> list: 2 | ans = list() 3 | eb = 1 << (maxlen << 3) if full else 256 4 | es = 1 5 | ls = 0 6 | for lb in range(maxlen if full else 1, maxlen + 1): 7 | assert eb == 1 << (lb << 3) 8 | assert es == x ** ls 9 | 10 | if unbase: 11 | while eb >= es * x: 12 | ls += 1 13 | es *= x 14 | assert eb >= es 15 | assert eb < es * x 16 | p = es / eb 17 | else: 18 | while eb > es: 19 | ls += 1 20 | es *= x 21 | assert eb <= es 22 | assert eb * x > es 23 | p = eb / es 24 | ans.append((p, ls, lb,)) 25 | if eb == es: 26 | break 27 | eb <<= 8 28 | return sorted(ans) 29 | 30 | 31 | for i in range(2, 256): 32 | a = basesize(i, unbase = True) 33 | print(i, '%.2f %d %d' % a[-1]) 34 | # if i % 8 == 0: 35 | # print() 36 | # print('{%d,%d},' % a[-1][1:], end='') 37 | 38 | # s = open('rd.key', 'rb').read() 39 | # while s: 40 | # while len(s) < 5: 41 | # s = s+b'\x00' 42 | # a = int.from_bytes(s[:5], 'little') 43 | # a = int.from_bytes(s[:5], 'big') 44 | # print('%012d' % a, end=' ') 45 | # s = s[5:] 46 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # Multiple Keys for 1 File 2 | 3 | 多文件多密钥打包成一个大文件. 4 | 5 | 给一个正确的密钥,可以提取对应文件. 6 | 7 | 同时,你可以生成多个部分真部分假的密钥序列.这样,你可以在受到胁迫的情况下安全地隐藏想要隐藏的文件. 8 | 9 | ## 算法介绍 10 | 11 | ### 理想状态的函数 12 | 13 | $$ 14 | \rm Encrypt(key_1,\cdots,key_n,file_1,\cdots,file_n)=bigfile, 15 | $$ 16 | 17 | $$ 18 | \rm Decrypt(key_x,bigfile)=file_x. 19 | $$ 20 | 21 | 就算知道了一个 $\rm key,$ 还是只能暴力破解. 22 | 23 | ### 序列 24 | 25 | 编码过程中,需要用每个 $\rm key_x$ 生成序列 $\rm l_x.$ 它通过环状结构成为无限序列,且满足 26 | 27 | $$ 28 | \rm l_i[k]\neq l_j[k],l_i[k]\in\N\cap[0,n),\forall i\neq j,\forall k. 29 | $$ 30 | 31 | 可见,这个要求还是很苛刻的,所以建议使用程序生成随机密码序列. 32 | 33 | $\rm key\to int(base\ n)\to l_x.$ 34 | 35 | ### 文件结构 36 | 37 | 大文件的第 $\rm k$ 段连续的 $\rm n$ 个bit中的第 $\rm l_x[k]+1$ 个,恰好是小文件 $\rm file_x$ 的第 $\rm k$ 位,即 38 | 39 | $$ 40 | \rm bigfile[(k-1)*n+l_x[k]]=file_x[k]. 41 | $$ 42 | 43 | 当娶不到 $\rm file_x[k],$ 随机生成即可. 44 | 45 | ### 暴力破解时间复杂度 46 | 47 | 已知 $k$ 个 $\rm key,$ 长度 $l,$ 文件数量 $n.$ 48 | 49 | 则下标序列的最大最小循环节长度为 $m=\lceil\log_n256^l\rceil=\lceil8l\frac{\ln2}{\ln n}\rceil,$ 遍历所有可能密码的时间复杂度为 $O((n-k)^m)\simeq O(256^l).$ 50 | 51 | ### 其它可能的破解方式 52 | 53 | 对方知道其中一个文件 $\rm file_x[k],$ 但不知道文件数量、任何密码及其长度。此时,暴力破解出此文件对应的密码所需时间复杂度望为 $O(m^2n\log n).$ 54 | 55 | ## 接口 56 | 57 | ### encrypt 58 | 59 | #### 函数声明 60 | 61 | ```cpp 62 | int encrypt(int n, int kn, char **ks, char **fs, const char *big = "big.bin"); 63 | ``` 64 | 65 | #### 变量 66 | 67 | |Name |Type |Explain| 68 | |- |- |-| 69 | |`n` |`int` |文件(及密钥)数量 $n$| 70 | |`ks` |`int` |密钥长度 $l$| 71 | |`fs` |`char **` |小文件路径| 72 | |`big` |`const char *` |大文件(生成)路径| 73 | |return |`int` |`0` 为正常返回| 74 | 75 | #### 功能 76 | 77 | 保存密钥并生成大文件. 78 | 79 | ### decrypt 80 | 81 | #### 函数声明 82 | 83 | ```cpp 84 | int decrypt(const char *fk, const char *big, const char *fx); 85 | ``` 86 | 87 | #### 变量 88 | 89 | |Name |Type |Explain| 90 | |- |- |-| 91 | |`fk` |`const char *` |密钥文件路径| 92 | |`big` |`const char *` |大文件路径| 93 | |`fx` |`const char *` |对应小文件(生成)路径| 94 | |return |`int` |`0` 为正常返回| 95 | 96 | #### 功能介绍 97 | 98 | Decrypt 出对应小文件. 99 | -------------------------------------------------------------------------------- /basen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int basen[256][2] = { 4 | {0, 0}, {0, 0}, {8, 1}, {5, 1}, {4, 1}, {24, 7}, {3, 1}, {17, 6}, 5 | {8, 3}, {5, 2}, {12, 5}, {16, 7}, {11, 5}, {15, 7}, {2, 1}, {2, 1}, 6 | {2, 1}, {15, 8}, {15, 8}, {15, 8}, {11, 6}, {9, 5}, {7, 4}, {7, 4}, 7 | {12, 7}, {12, 7}, {5, 3}, {5, 3}, {13, 8}, {13, 8}, {13, 8}, {8, 5}, 8 | {8, 5}, {11, 7}, {11, 7}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, 9 | {3, 2}, {10, 7}, {10, 7}, {10, 7}, {10, 7}, {10, 7}, {10, 7}, {10, 7}, 10 | {10, 7}, {7, 5}, {7, 5}, {7, 5}, {7, 5}, {11, 8}, {11, 8}, {11, 8}, 11 | {11, 8}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, 12 | {4, 3}, {9, 7}, {9, 7}, {9, 7}, {9, 7}, {9, 7}, {9, 7}, {9, 7}, 13 | {9, 7}, {9, 7}, {9, 7}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, 14 | {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {6, 5}, {6, 5}, {6, 5}, 15 | {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, 16 | {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {7, 6}, {7, 6}, 17 | {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, 18 | {7, 6}, {7, 6}, {7, 6}, {7, 6}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, 19 | {8, 7}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, 20 | {8, 7}, {9, 8}, {9, 8}, {9, 8}, {9, 8}, {9, 8}, {9, 8}, {9, 8}, 21 | {9, 8}, {9, 8}, {9, 8}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 22 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 23 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 24 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 25 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 26 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 27 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 28 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 29 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 30 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 31 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 32 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 33 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 34 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, 35 | {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}; 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multiple Keys for 1 File 2 | 3 | [中文](README_cn.md) 4 | 5 | Multiple keys for multiple files packed into one large file. 6 | 7 | Given a key, you can extract the corresponding file. 8 | 9 | At the same time, you can generate multiple partly true and partly false key sequences. In this way, you can safely hide the files you want to hide under duress. 10 | 11 | ## Algorithm 12 | 13 | ### Function 14 | 15 | $$ 16 | \rm Encrypt(key_1,\cdots,key_n,file_1,\cdots,file_n)=bigfile, 17 | $$ 18 | 19 | $$ 20 | \rm Decrypt(key_x,bigfile)=file_x. 21 | $$ 22 | 23 | Even if know one $\rm key$, the rest still needs to be brute-force attacked. 24 | 25 | ### Sequence 26 | 27 | In the encoding process, each $\rm key_x$ is used to generate the sequence $\rm l_x.$ It becomes an infinite sequence through the ring structure, and satisfies 28 | 29 | $$ 30 | \rm l_i[k]\neq l_j[k],l_i[k]\in\N\cap[0,n),\forall i\neq j,\forall k. 31 | $$ 32 | 33 | As you can see, these requirements are very demanding. So it is recommended to use the program to generate key sequences. 34 | 35 | $\rm key\to int(base\ n)\to l_x.$ 36 | 37 | ### File Structure 38 | 39 | The $\rm l_x$-th bit of the $\rm k$-th consecutive $\rm n$ bits of the large file, is exactly the $\rm k$-th bit of the small file $\rm file_x,$ i.e. 40 | 41 | $$ 42 | \rm bigfile[(k-1)*n+l_x[k]]=file_x[k]. 43 | $$ 44 | 45 | When $\rm file_x[k]$ is not available, randomly generate it. 46 | 47 | ### Brute-force Attack Time Complexity 48 | 49 | $k$ keys, key length $l$ and number of files $n$ are known. 50 | 51 | The maximum minimum cycle length of the subscript sequence is $m=\lceil\log_n256^l\rceil=\lceil8l\frac{\ln2}{\ln n}\rceil,$ and the time complexity of traversing all possible passwords is $O((n-k)^m)\simeq O(256^l).$ 52 | 53 | ### Other Possible Ways to Crack 54 | 55 | One of the files is known, but the number of files, any keys or its length are not known. In this case, the time complexity required to crack the key corresponding to this file by means of brute-force attacking is $O(m^2n\log n).$ 56 | 57 | ## Interface 58 | 59 | ### encrypt 60 | 61 | #### Declaration 62 | 63 | ```cpp 64 | int encrypt(int n, int kn, char **ks, char **fs, const char *big = "big.bin"); 65 | ``` 66 | 67 | #### Variables 68 | 69 | |Name |Type |Explain| 70 | |- |- |-| 71 | |`n` |`int` |the number of files (and keys) $n$| 72 | |`ks` |`int` |key length $l$| 73 | |`fs` |`char **` |small file path| 74 | |`big` |`const char *` |large file (generation) path| 75 | |return |`int` |`0` is the normal return| 76 | 77 | #### Function 78 | 79 | Save the keys and generate the large file. 80 | 81 | ### decrypt 82 | 83 | #### Declaration 84 | 85 | ```cpp 86 | int decrypt(const char *fk, const char *big, const char *fx); 87 | ``` 88 | 89 | #### Variables 90 | 91 | |Name |Type |Explain| 92 | |- |- |-| 93 | |`fk` |`const char *` |key file path| 94 | |`big` |`const char *` |large file path| 95 | |`fx` |`const char *` |corresponding small file (generation) path| 96 | |return |`int` |`0` is the normal return| 97 | 98 | #### Function 99 | 100 | Decrypt the corresponding small file. 101 | -------------------------------------------------------------------------------- /mk1f.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "basen.h" 9 | 10 | #define LL long long 11 | #define ULL unsigned long long 12 | #define B unsigned char 13 | 14 | namespace Mk1f { 15 | 16 | const int MAX_N = 255; 17 | int flg_srand_time = 0; 18 | const int BUFFER_SIZE = 1024; 19 | 20 | inline void throws(const char *s) { 21 | throw std::runtime_error(std::string(s)); 22 | } 23 | 24 | inline int size_of_file(const char *pth) { 25 | FILE *fp = fopen(pth, "rb"); 26 | if (!fp) { 27 | return -1; 28 | } 29 | fseek(fp, 0, SEEK_END); 30 | int size = ftell(fp); 31 | fclose(fp); 32 | return size; 33 | } 34 | 35 | class Reader { 36 | private: 37 | FILE *fp; 38 | B *buffer; 39 | ULL t = 0, size; 40 | int t1 = 0, t2 = 0; 41 | 42 | public: 43 | int flg_rand = 1, flg_head = 1; 44 | Reader(const char *pth, int flg_head); 45 | inline int read_bit(); 46 | inline ULL read_bits(int x); 47 | inline int read_bit_of_n(int x, int n); 48 | inline void fre(); 49 | ~Reader(); 50 | }; 51 | 52 | Reader::Reader(const char *pth, int flg_head = 0) { 53 | buffer = (B *)malloc(BUFFER_SIZE); 54 | if (!flg_srand_time) { 55 | srand(time(nullptr)); 56 | flg_srand_time = 1; 57 | } 58 | size = size_of_file(pth); 59 | flg_rand = 0; 60 | fp = fopen(pth, "rb"); 61 | if (!fp) { 62 | throws("FileNotExist"); 63 | } 64 | if (flg_head) { 65 | this->flg_head = 1; 66 | ULL a = size; 67 | for (int i = 7; i >= 0; i--) { 68 | buffer[i] = (a & 255) ^ (buffer[i + 8] = rand() & 255) ^ (buffer[i + 16] = rand() & 255); 69 | a >>= 8; 70 | } 71 | } else { 72 | this->flg_head = 0; 73 | t1 = 0; 74 | fread(buffer, 1, BUFFER_SIZE, fp); 75 | } 76 | } 77 | 78 | inline int Reader::read_bit() { 79 | if (flg_rand) { 80 | return rand() & 1; 81 | } 82 | int ans = (buffer[t1] >> (7 - t2)) & 1; 83 | t2++; 84 | if (t2 == 8) { 85 | t2 = 0; 86 | t1++; 87 | if (flg_head) { 88 | if (t1 >= 24) { 89 | flg_head = 0; 90 | t1 = 0; 91 | fread(buffer, 1, BUFFER_SIZE, fp); 92 | } 93 | } else { 94 | t++; 95 | if (t >= size) { 96 | fclose(fp); 97 | flg_rand = 1; 98 | } 99 | if (t1 == BUFFER_SIZE) { 100 | t1 = 0; 101 | fread(buffer, 1, BUFFER_SIZE, fp); 102 | } 103 | } 104 | } 105 | return ans; 106 | } 107 | 108 | inline ULL Reader::read_bits(int x) { 109 | if (x < 0 || x > 64) { 110 | throws("Reader.read_bits: x out of range"); 111 | } 112 | ULL ans = 0; 113 | for (int i = 0; i < x; i++) { 114 | ans = ans << 1 | read_bit(); 115 | } 116 | return ans; 117 | } 118 | 119 | inline int Reader::read_bit_of_n(int x, int n) { 120 | int ans; 121 | int k = 0; 122 | for (; k <= x; k++) { 123 | ans = read_bit(); 124 | } 125 | for (; k < n; k++) { 126 | read_bit(); 127 | } 128 | return ans; 129 | } 130 | 131 | inline void Reader::fre() { 132 | if (fp) { 133 | fclose(fp); 134 | fp = nullptr; 135 | } 136 | if (buffer) { 137 | free(buffer); 138 | buffer = nullptr; 139 | } 140 | size = t = t1 = t2 = 0; 141 | } 142 | 143 | Reader::~Reader() { 144 | fre(); 145 | } 146 | 147 | class Writer { 148 | private: 149 | FILE *fp; 150 | ULL t = 0; 151 | int t1 = 0, t2 = 0; 152 | B *buffer; 153 | 154 | public: 155 | Writer(const char *pth); 156 | inline void write_bit(int b); 157 | inline void write_bits(ULL b, int x); 158 | inline void flush(); 159 | inline void release(); 160 | inline void fre(); 161 | ~Writer(); 162 | }; 163 | 164 | Writer::Writer(const char *pth) { 165 | buffer = (B *)malloc(BUFFER_SIZE); 166 | memset(buffer, 0, BUFFER_SIZE); 167 | fp = fopen(pth, "wb"); 168 | if (!fp) { 169 | throws("CannotOpenFile"); 170 | } 171 | } 172 | 173 | inline void Writer::write_bit(int b) { 174 | buffer[t1] = buffer[t1] << 1 | b; 175 | t2++; 176 | if (t2 == 8) { 177 | t2 = 0; 178 | t1++; 179 | t++; 180 | if (t1 == BUFFER_SIZE) { 181 | fwrite(buffer, 1, BUFFER_SIZE, fp); 182 | memset(buffer, 0, BUFFER_SIZE); 183 | t1 = 0; 184 | } 185 | } 186 | } 187 | 188 | inline void Writer::write_bits(ULL b, int x) { 189 | if (x < 0 || x > 64) { 190 | throws("Writer.write_bits: x out of range"); 191 | } 192 | x--; 193 | for (; x >= 0; x--) { 194 | write_bit((b & (1 << x)) ? 1 : 0); 195 | } 196 | } 197 | 198 | inline void Writer::flush() { 199 | const int a = t1 + (t2 ? 1 : 0); 200 | if (a) { 201 | fwrite(buffer, 1, a, fp); 202 | } 203 | t1 = t2 = 0; 204 | } 205 | 206 | inline void Writer::fre() { 207 | flush(); 208 | if (fp) { 209 | fclose(fp); 210 | fp = nullptr; 211 | } 212 | if (buffer) { 213 | free(buffer); 214 | buffer = nullptr; 215 | } 216 | t = 0; 217 | } 218 | 219 | Writer::~Writer() { 220 | fre(); 221 | } 222 | 223 | class Keys { 224 | private: 225 | int n, num = 0, blocks = 0; 226 | int n_0, n_1; 227 | B *map, *inverse_map; 228 | inline int convert(B *s, int size); 229 | 230 | public: 231 | Keys(int n, int loop_size); 232 | 233 | inline Keys *clone(int x); 234 | 235 | inline int add(B *k); 236 | inline int add(const char *k); 237 | inline int read(const char *pth); 238 | inline int random(); 239 | inline int release(); 240 | 241 | inline int set_blocks(int blocks); 242 | inline int set_loop_size(int loop_size); 243 | inline int set_key_size(int key_size); 244 | 245 | // inline B get_map(int x); 246 | inline B *get_key(int x) const; 247 | inline int save_key(int x, const char *pth) const; 248 | inline int save_keys(const char *pth) const; 249 | inline void pt(int x) const; 250 | inline int get_n() const; 251 | inline int get_num() const; 252 | inline int get_blocks() const; 253 | inline int get_loop_size() const; 254 | inline int get_key_size() const; 255 | 256 | inline int encrypt(char **fs, const char *big) const; 257 | inline int decrypt(int x, const char *big, const char *fx) const; 258 | 259 | inline void fre(); 260 | ~Keys(); 261 | }; 262 | 263 | inline int Keys::convert(B *s, int size) { 264 | if (!num && blocks <= 0) { 265 | set_key_size(size); 266 | } else { 267 | if (size + n_1 <= get_key_size()) { 268 | return -1; 269 | } 270 | } 271 | int st = 0; 272 | for (int i = 0; i < get_loop_size() * n; i += n_0 * n) { 273 | ULL reg = 0; 274 | for (int j = 0; j < n_1; j++) { 275 | reg <<= 8; 276 | if (st < size) { 277 | reg |= s[st++]; 278 | } 279 | } 280 | for (int j = i + (n_0 - 1) * n; j >= i; j -= n) { 281 | const int x = reg % n; 282 | if (inverse_map[j + x] < num) { 283 | return 1; 284 | } 285 | inverse_map[j + x] = num; 286 | map[j + num] = x; 287 | reg /= n; 288 | } 289 | } 290 | num++; 291 | return 0; 292 | } 293 | 294 | Keys::Keys(int n, int loop_size = 0) { 295 | this->n = n; 296 | n_0 = basen[n][0]; 297 | n_1 = basen[n][1]; 298 | if (loop_size > 0) { 299 | set_loop_size(loop_size); 300 | } 301 | if (!flg_srand_time) { 302 | srand(time(nullptr)); 303 | flg_srand_time = 1; 304 | } 305 | } 306 | 307 | inline Keys *Keys::clone(int x) { 308 | if (!num || x > num) { 309 | return nullptr; 310 | } 311 | Keys *ans = new Keys(n, get_loop_size()); 312 | for (int i = 0; i < x; i++) { 313 | ans->add(get_key(i)); 314 | } 315 | return ans; 316 | } 317 | 318 | inline int Keys::add(B *k) { 319 | return convert(k, strlen((char *)k)); 320 | } 321 | inline int Keys::add(const char *k) { 322 | return add((B *)k); 323 | } 324 | 325 | inline int Keys::read(const char *pth) { 326 | int size = size_of_file(pth); 327 | if (size <= 0) { 328 | return -1; 329 | } 330 | FILE *fp = fopen(pth, "rb"); 331 | B *s = (B *)malloc(size); 332 | fread(s, 1, size, fp); 333 | return convert(s, size); 334 | } 335 | 336 | inline int Keys::random() { 337 | if (blocks <= 0) { 338 | return -1; 339 | } 340 | const int range = n - num; 341 | 342 | for (int j = 0; j < get_loop_size() * n; j += n) { 343 | int x = 0, y = range * rand() / (RAND_MAX + 1); 344 | for (; x < n; x++) { 345 | if (inverse_map[j + x] >= num) { 346 | if (!y--) { 347 | break; 348 | } 349 | } 350 | } 351 | if (x >= n) { 352 | throws("Keys.random: x out of range"); 353 | } 354 | inverse_map[j + x] = num; 355 | map[j + num] = x; 356 | } 357 | 358 | num++; 359 | return 0; 360 | } 361 | 362 | inline int Keys::release() { 363 | while (num < n) { 364 | int z = random(); 365 | if (z) { 366 | return z; 367 | } 368 | } 369 | return 0; 370 | } 371 | 372 | inline int Keys::set_blocks(int blocks) { 373 | if (num) { 374 | return -1; 375 | } 376 | if (blocks <= 0) { 377 | return blocks; 378 | } 379 | const int map_size = blocks * n_0 * n; 380 | if (this->blocks) { 381 | realloc(map, map_size); 382 | realloc(inverse_map, map_size); 383 | } else { 384 | map = (B *)malloc(map_size); 385 | inverse_map = (B *)malloc(map_size); 386 | } 387 | memset(inverse_map, -1, map_size); 388 | return this->blocks = blocks; 389 | } 390 | inline int Keys::set_loop_size(int loop_size) { 391 | return set_blocks((loop_size - 1) / n_0 + 1); 392 | } 393 | inline int Keys::set_key_size(int key_size) { 394 | return set_blocks((key_size - 1) / n_1 + 1); 395 | } 396 | 397 | inline void Keys::pt(int x) const { 398 | for (int i = 0; i < get_loop_size() * n; i += n) { 399 | printf("%x", map[i + x]); 400 | } 401 | printf("\n"); 402 | } 403 | 404 | inline B *Keys::get_key(int x) const { 405 | B *ans = (B *)malloc(get_key_size()); 406 | int st = 0; 407 | for (int i = 0; i < get_loop_size() * n; i += n_0 * n) { 408 | ULL reg = 0; 409 | for (int j = i; j < i + n_0 * n; j += n) { 410 | reg *= n; 411 | reg += map[j + x]; 412 | } 413 | for (int j = n_1 - 1 + st; j >= st; j--) { 414 | ans[j] = reg & (ULL)255; 415 | reg >>= 8; 416 | } 417 | st += n_1; 418 | } 419 | return ans; 420 | } 421 | 422 | inline int Keys::save_key(int x, const char *pth) const { 423 | FILE *fp = fopen(pth, "wb"); 424 | if (!fp) { 425 | return -1; 426 | } 427 | fwrite(get_key(x), 1, get_key_size(), fp); 428 | fclose(fp); 429 | return 0; 430 | } 431 | 432 | inline int Keys::save_keys(const char *pth = "keys/%d.key") const { 433 | int ans = 0; 434 | for (int i = 0; i < n; i++) { 435 | char s[512]; 436 | sprintf(s, pth, i); 437 | ans += save_key(i, s); 438 | } 439 | return ans; 440 | } 441 | 442 | inline int Keys::get_n() const { 443 | return n; 444 | } 445 | inline int Keys::get_num() const { 446 | return num; 447 | } 448 | inline int Keys::get_blocks() const { 449 | return blocks; 450 | } 451 | inline int Keys::get_loop_size() const { 452 | return blocks * n_0; 453 | } 454 | inline int Keys::get_key_size() const { 455 | return blocks * n_1; 456 | } 457 | 458 | inline void Keys::fre() { 459 | int n, num = blocks = n_0 = n_1 = 0; 460 | if (map) { 461 | free(map); 462 | map = nullptr; 463 | } 464 | if (inverse_map) { 465 | free(inverse_map); 466 | inverse_map = nullptr; 467 | } 468 | } 469 | 470 | Keys::~Keys() { 471 | fre(); 472 | } 473 | 474 | inline int Keys::encrypt(char **fs, const char *big = "big.bin") const { 475 | if (num ^ n) { 476 | // release(); 477 | return -1; 478 | } 479 | 480 | Reader **rp = (Reader **)malloc(sizeof(Reader *) * n); 481 | for (int i = 0; i < n; i++) { 482 | rp[i] = new Reader(fs[i], 1); 483 | } 484 | Writer *wp = new Writer(big); 485 | wp->write_bits(n, 32); 486 | 487 | const int max_ap = get_loop_size() * n; 488 | int ap = 0; 489 | int flg = 1; 490 | while (flg) { 491 | for (int j = 0; j < 8; j++) { 492 | for (int i = 0; i < n; i++) { 493 | int x = inverse_map[ap++]; 494 | int y = rp[x]->read_bit(); 495 | wp->write_bit(y); 496 | } 497 | if (ap >= max_ap) { 498 | ap = 0; 499 | } 500 | } 501 | flg = 0; 502 | for (int i = 0; i < n; i++) { 503 | if (!rp[i]->flg_rand) { 504 | flg = 1; 505 | break; 506 | } 507 | } 508 | } 509 | 510 | wp->fre(); 511 | delete wp; 512 | for (int i = 0; i < n; i++) { 513 | rp[i]->fre(); 514 | free(rp[i]); 515 | } 516 | delete rp; 517 | return 0; 518 | } 519 | 520 | // inline B Keys::get_map(int x = -1) { 521 | // static int ap; 522 | // if (x > 0) { 523 | // ap = x; 524 | // } 525 | // B ans = *(map + ap); 526 | // ap += n; 527 | // if (ap >= get_loop_size() * n) { 528 | // ap = 0; 529 | // } 530 | // return ans; 531 | // } 532 | 533 | inline int Keys::decrypt(int x, const char *big, const char *fx) const { 534 | if (num <= x) { 535 | return -1; 536 | } 537 | Reader *rp = new Reader(big, 0); 538 | Writer *wp = new Writer(fx); 539 | 540 | const int _n = rp->read_bits(32); 541 | if (_n ^ n) { 542 | return _n; 543 | } 544 | 545 | const int max_ap = get_loop_size() * n; 546 | int ap = x; 547 | ULL a = 0; 548 | for (int i = 0; i < 3; i++) { 549 | ULL b = 0; 550 | for (int j = 0; j < 64; j++) { 551 | b = b << 1 | rp->read_bit_of_n(*(map + ap), n); 552 | ap += n; 553 | if (ap >= max_ap) { 554 | ap = x; 555 | } 556 | } 557 | a ^= b; 558 | } 559 | 560 | // printf("%lld\n", a); 561 | 562 | for (int i = 0; i < a << 3; i++) { 563 | wp->write_bit(rp->read_bit_of_n(*(map + ap), n)); 564 | ap += n; 565 | if (ap >= max_ap) { 566 | ap = x; 567 | } 568 | } 569 | 570 | wp->fre(); 571 | delete wp; 572 | rp->fre(); 573 | delete rp; 574 | return 0; 575 | } 576 | 577 | inline int encrypt(int n, int ks, char **fs, const char *big = "big.bin") { 578 | int ans = 0; 579 | Keys *p = new Keys(n); 580 | p->set_key_size(ks); 581 | p->release(); 582 | 583 | ans = p->save_keys(); 584 | if (ans) { 585 | return ans; 586 | } 587 | 588 | ans = p->encrypt(fs, big); 589 | p->fre(); 590 | delete p; 591 | return ans; 592 | } 593 | 594 | inline int decrypt(const char *fk, const char *big, const char *fx) { 595 | int ans = 0; 596 | Reader *rp = new Reader(big, 0); 597 | Keys *p = new Keys(rp->read_bits(32)); 598 | rp->fre(); 599 | delete rp; 600 | 601 | ans = p->read(fk); 602 | if (ans) { 603 | return ans; 604 | } 605 | 606 | ans = p->decrypt(0, big, fx); 607 | p->fre(); 608 | delete p; 609 | return ans; 610 | } 611 | 612 | }; // namespace Mk1f --------------------------------------------------------------------------------