1219 lines
62 KiB
Python
1219 lines
62 KiB
Python
|
#!/usr/bin/env python3
|
|||
|
#-*- coding: utf-8 -*-
|
|||
|
# kirmah/crypt.py
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
#
|
|||
|
# software : Kirmah <http://kirmah.sourceforge.net/>
|
|||
|
# version : 2.18
|
|||
|
# date : 2014
|
|||
|
# licence : GPLv3.0 <http://www.gnu.org/licenses/>
|
|||
|
# author : a-Sansara <[a-sansara]at[clochardprod]dot[net]>
|
|||
|
# copyright : pluie.org <http://www.pluie.org/>
|
|||
|
#
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
#
|
|||
|
# This file is part of Kirmah.
|
|||
|
#
|
|||
|
# Kirmah is free software (free as in speech) : you can redistribute it
|
|||
|
# and/or modify it under the terms of the GNU General Public License as
|
|||
|
# published by the Free Software Foundation, either version 3 of the License,
|
|||
|
# or (at your option) any later version.
|
|||
|
#
|
|||
|
# Kirmah is distributed in the hope that it will be useful, but WITHOUT
|
|||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|||
|
# more details.
|
|||
|
#
|
|||
|
# You should have received a copy of the GNU General Public License
|
|||
|
# along with Kirmah. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
#
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ module crypt ~~
|
|||
|
|
|||
|
from base64 import urlsafe_b64encode, b64decode
|
|||
|
from binascii import b2a_base64, a2b_base64
|
|||
|
from hashlib import sha256, md5
|
|||
|
from math import log, floor, ceil
|
|||
|
from random import choice
|
|||
|
from os import urandom
|
|||
|
from re import sub
|
|||
|
from mmap import mmap
|
|||
|
from ast import literal_eval
|
|||
|
from psr.sys import Sys, Io, Const
|
|||
|
from psr.log import Log
|
|||
|
from psr.mproc import Manager
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ methods ~~
|
|||
|
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def hash_sha256(data):
|
|||
|
"""Get a sha256 hash of str `data`
|
|||
|
:Returns: `str`
|
|||
|
"""
|
|||
|
return str(sha256(bytes(data,'utf-8')).hexdigest())
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def hash_sha256_file(path):
|
|||
|
"""Get a sha256 hash of str `data`
|
|||
|
:Returns: `str`
|
|||
|
"""
|
|||
|
return sha256(open(path, mode='rb').read()).hexdigest()
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def hash_md5_file(path):
|
|||
|
"""Get a md5 hash of file from path
|
|||
|
:Returns: `str`
|
|||
|
"""
|
|||
|
return md5(open(path, mode='rb').read()).hexdigest()
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def randomFrom(val, sval=0):
|
|||
|
"""Get a random number from range `sval=0` to `val`
|
|||
|
:Returns: `int`
|
|||
|
"""
|
|||
|
lst = list(range(sval,val))
|
|||
|
return choice(lst)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_NEVER)
|
|||
|
def represents_int(s):
|
|||
|
""""""
|
|||
|
try:
|
|||
|
if s is None : return False
|
|||
|
int(s)
|
|||
|
return True
|
|||
|
except ValueError:
|
|||
|
return False
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class KeyGen ~~
|
|||
|
|
|||
|
class KeyGen :
|
|||
|
|
|||
|
CHSET = [33, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 880, 881, 882, 883, 884, 885, 886, 887, 891, 892, 893, 894, 901, 902, 903, 904, 905, 906, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 106
|
|||
|
""""""
|
|||
|
LEN_FOOTPRINT = 24
|
|||
|
""""""
|
|||
|
SALT = '-¤-Kirmah-¤-'
|
|||
|
""""""
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self, length=1024, salt=None):
|
|||
|
""""""
|
|||
|
self.new(length, salt)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_PRIVATE)
|
|||
|
def _build(self,l):
|
|||
|
""""""
|
|||
|
r = Randomiz(len(self.CHSET),self.CHSET)
|
|||
|
self.key = ksin = kfoo = ''
|
|||
|
dic = {}
|
|||
|
for i in range(l):
|
|||
|
self.key += chr(r.get(False))
|
|||
|
if not self.key[i] in dic: dic[self.key[i]] = 1
|
|||
|
for c in dic: ksin += c
|
|||
|
for c in ksin[::-5]:
|
|||
|
if len(kfoo)>=self.LEN_FOOTPRINT: break
|
|||
|
kfoo += c
|
|||
|
self.mark = hash_sha256(self.salt+kfoo)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getMark(self, key=None):
|
|||
|
""""""
|
|||
|
dic = {}
|
|||
|
ksin = kfoo = ''
|
|||
|
if key is None :
|
|||
|
key = self.key
|
|||
|
for i in range(len(key)):
|
|||
|
if not key[i] in dic: dic[key[i]] = 1
|
|||
|
for c in dic: ksin += c
|
|||
|
for c in sorted(ksin)[::-5]:
|
|||
|
if len(kfoo)>=self.LEN_FOOTPRINT: break
|
|||
|
kfoo += c
|
|||
|
return hash_sha256(self.salt+kfoo)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def new(self, length, salt=None):
|
|||
|
""""""
|
|||
|
if salt == None : self.salt = self.SALT
|
|||
|
else : self.salt = salt
|
|||
|
self._build(length)
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class ConfigKey ~~
|
|||
|
|
|||
|
class ConfigKey:
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self, key=None, salt=None, psize=19710000):
|
|||
|
""""""
|
|||
|
self.key = bytes(key,'utf-8') if key is not None else self._build()
|
|||
|
self.salt = str(self.key[::-10]) if salt is None else salt
|
|||
|
self.psize = psize
|
|||
|
self.noiser = Noiser(self.key)
|
|||
|
self.rdmz = Randomiz(1)
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def sumNumber(s,count):
|
|||
|
""""""
|
|||
|
return sum([ int(c) for j,c in enumerate(s) if represents_int(c)][0:count])
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getHashList(self,name,count,noSorted=False):
|
|||
|
""""""
|
|||
|
self.rdmz.new(count)
|
|||
|
dic, lst, hroot = {}, [], hash_sha256(self.salt+name)
|
|||
|
|
|||
|
srdl = Kirmah.getRandomListFromKey(self.key, count)
|
|||
|
#~ srdl = getRandomListFromKey(self.key, count)
|
|||
|
for i in range(count) :
|
|||
|
self.noiser.build(i,ConfigKey.sumNumber(hash_sha256(str(i)+self.salt+name),1 if i%2 else 2))
|
|||
|
d = str(i).rjust(2,'0')
|
|||
|
# part n°, hash, lns, lne, pos
|
|||
|
hpart = hash_sha256(self.salt+name+'.part'+d)[:-3]+str(ord(hroot[i])).rjust(3,'0')
|
|||
|
lst.append((i, hpart, self.noiser.lns, self.noiser.lne, self.rdmz.get(), srdl[i]))
|
|||
|
dic['head'] = [name,count,hroot,self.getKey()]
|
|||
|
if not noSorted :
|
|||
|
lst = sorted(lst, key=lambda lst: lst[4])
|
|||
|
dic['data'] = lst
|
|||
|
return dic
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_PRIVATE)
|
|||
|
def _build(self,l=48):
|
|||
|
""""""
|
|||
|
kg = KeyGen(l)
|
|||
|
k = urlsafe_b64encode(bytes(kg.key,'utf-8'))
|
|||
|
return k
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getKey(self):
|
|||
|
""""""
|
|||
|
return str(self.key,'utf-8')
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class Kirmah ~~
|
|||
|
|
|||
|
class KirmahHeader:
|
|||
|
|
|||
|
COMP_NONE = 0
|
|||
|
COMP_ALL = 1
|
|||
|
COMP_END = 2
|
|||
|
|
|||
|
POS_VERS = 5
|
|||
|
POS_COMP = 7
|
|||
|
POS_RAND = 12
|
|||
|
POS_MIX = 15
|
|||
|
POS_SEC = 18
|
|||
|
POS_END = 22
|
|||
|
|
|||
|
ID = b'\x05\xd9\x83MH'
|
|||
|
MODE_COMP = b'Z'
|
|||
|
MODE_RAND = b'R'
|
|||
|
MODE_MIX = b'M'
|
|||
|
MODE_SEC = b'S'
|
|||
|
|
|||
|
"""
|
|||
|
|
|||
|
ex : كMH02Z2499R42M26S0055
|
|||
|
|
|||
|
5o : كMH - File type id (FIXED)
|
|||
|
|
|||
|
|
|||
|
2o : 02 - Version (majeur number)
|
|||
|
version.rjust(2,'0')
|
|||
|
|
|||
|
5o : Z?? - Compression Mode
|
|||
|
'?' ord(chr mark pos)%2==0
|
|||
|
? compression ON
|
|||
|
: compression OFF
|
|||
|
'?' ord(chr mark pos)%2==0
|
|||
|
? compression all
|
|||
|
: compression end
|
|||
|
|
|||
|
3o : R? - Random Mode
|
|||
|
'?' ord(chr mark pos)%2==0
|
|||
|
? random ON
|
|||
|
: randon OFF
|
|||
|
|
|||
|
3o : M? - Mix Mode
|
|||
|
'?' ord(chr mark pos)%2==0
|
|||
|
? mix ON
|
|||
|
: mix OFF
|
|||
|
|
|||
|
3o : S??? - Secure Mode
|
|||
|
'?' mark[dlen%len(mark)].rjust(3,'0')
|
|||
|
|
|||
|
"""
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self, version, mark, cmode=1, rmode=True, mmode=True):
|
|||
|
""""""
|
|||
|
self.version = bytes(str(int(float(version))).rjust(2,'0'),'utf-8')
|
|||
|
self.mark = mark
|
|||
|
self.cmode = cmode
|
|||
|
self.rmode = rmode
|
|||
|
self.mmode = mmode
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getPositionnalChar(self, sindex, test=True):
|
|||
|
""""""
|
|||
|
pc = None
|
|||
|
for i, c in enumerate(self.mark[sindex:]) :
|
|||
|
if c % 2 == 0 and test or not test and c % 2 != 0 :
|
|||
|
pc = i+sindex
|
|||
|
break
|
|||
|
return pc
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def checkPositionnalChar(self, pc):
|
|||
|
""""""
|
|||
|
return ord(self.mark[pc:pc+1])%2==0
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def buildHeader(self, dlen, cmode=None, rmode=None, mmode=None):
|
|||
|
""""""
|
|||
|
if cmode is None : cmode = self.cmode
|
|||
|
if rmode is None : rmode = self.rmode
|
|||
|
if mmode is None : mmode = self.mmode
|
|||
|
nocomp = cmode is self.COMP_NONE
|
|||
|
cmpc1 = self.getPositionnalChar(1, not nocomp)
|
|||
|
cmpc2 = self.getPositionnalChar(cmpc1+5, cmode is self.COMP_ALL)
|
|||
|
rmpc = self.getPositionnalChar(cmpc2+5, rmode)
|
|||
|
mmpc = self.getPositionnalChar(rmpc+5, mmode)
|
|||
|
smpc = self.mark[dlen%len(self.mark)]
|
|||
|
head = [self.ID, self.version, self.MODE_COMP, Io.bytes(str(cmpc1).rjust(2,'0')), Io.bytes(str(cmpc2).rjust(2,'0')), self.MODE_RAND, Io.bytes(str(rmpc).rjust(2,'0')), self.MODE_MIX, Io.bytes(str(mmpc).rjust(2,'0')), self.MODE_SEC, Io.bytes(str(smpc).rjust(3,'0'))]
|
|||
|
return b''.join(head)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def readHeader(self, header):
|
|||
|
""""""
|
|||
|
|
|||
|
isKmh, vers, cmode, rmode, mmode, smode, pc1, badKmh = header[:self.POS_VERS] == self.ID, None, None , None, None, None, None, False
|
|||
|
if isKmh :
|
|||
|
vers = int(header[self.POS_VERS:self.POS_VERS+2])
|
|||
|
if header[self.POS_COMP:self.POS_COMP+1] == self.MODE_COMP :
|
|||
|
if self.checkPositionnalChar(int(header[self.POS_COMP+1:self.POS_COMP+3])) :
|
|||
|
cmode = self.COMP_ALL if self.checkPositionnalChar(int(header[self.POS_COMP+3:self.POS_COMP+5])) else self.COMP_END
|
|||
|
else :
|
|||
|
cmode = self.COMP_NONE
|
|||
|
else :
|
|||
|
badKmh = True
|
|||
|
|
|||
|
if header[self.POS_RAND:self.POS_RAND+1] == self.MODE_RAND :
|
|||
|
rmode = self.checkPositionnalChar(int(header[self.POS_RAND+1:self.POS_RAND+3]))
|
|||
|
else :
|
|||
|
badKmh = True
|
|||
|
|
|||
|
if header[self.POS_MIX:self.POS_MIX+1] == self.MODE_MIX :
|
|||
|
mmode = self.checkPositionnalChar(int(header[self.POS_MIX+1:self.POS_MIX+3]))
|
|||
|
else :
|
|||
|
badKmh = True
|
|||
|
|
|||
|
if header[self.POS_SEC:self.POS_SEC+1] == self.MODE_SEC :
|
|||
|
smode = chr(int(header[self.POS_SEC+1:self.POS_SEC+4]))
|
|||
|
else : badKmh = True
|
|||
|
|
|||
|
return { 'version':vers, 'cmode':cmode, 'rmode':rmode, 'mmode':mmode,'smode':smode} if isKmh and not badKmh else {}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class Kirmah ~~
|
|||
|
|
|||
|
class Kirmah:
|
|||
|
|
|||
|
VERSION = '2.1'
|
|||
|
EXT = '.kmh'
|
|||
|
EXT_TARK = '.tark'
|
|||
|
DIR_OUTBOX = ''
|
|||
|
DIR_INBOX = ''
|
|||
|
DIR_DEPLOY = ''
|
|||
|
DIR_TEMP = ''
|
|||
|
KMP_FILE = '.kmp'
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self, key, mark=None, headcompress=2, headrandom=True, headmix=True):
|
|||
|
""""""
|
|||
|
self.key = Io.bytes(key)
|
|||
|
self.mark = KeyGen(len(key)).getMark(key) if mark is None else mark
|
|||
|
self.mark2 = hash_sha256(self.mark) + self.mark[::-1]
|
|||
|
self.ck = ConfigKey(self.mark2)
|
|||
|
self.kh = KirmahHeader(Kirmah.VERSION, Io.bytes(self.mark), headcompress, headrandom, headmix)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def compress_start(self, fromPath, toPath, compress=True, lvl=9, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
data = fi.read() if not compress else Io.gzcompress(fi.read(), lvl)
|
|||
|
fo.write(b2a_base64(data))
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def uncompress_start(self, fromPath, toPath, decompress=True, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
data = a2b_base64(fi.read())
|
|||
|
fo.write(data if not decompress else Io.gzdecompress(data))
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def compress_end(self, fromPath, toPath, compress=True, lvl=9, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
data = fi.read()
|
|||
|
if compress : data = Io.gzcompress(data, lvl)
|
|||
|
header = self.kh.buildHeader(len(data))
|
|||
|
fo.write(header)
|
|||
|
fo.write(data)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def uncompress_end(self, fromPath, toPath, decompress=True, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
fi.seek(self.kh.POS_END)
|
|||
|
fo.write(fi.read() if not decompress else Io.gzdecompress(fi.read()))
|
|||
|
|
|||
|
@Log(Const.LOG_ALL)
|
|||
|
def encryptStr(self, data, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
s, lk, i = [], len(self.key), 0
|
|||
|
for c in data:
|
|||
|
if lk-i <= 0:
|
|||
|
i = 0
|
|||
|
if Sys.is_cli_cancel(): break
|
|||
|
s.append(chr(c + i//4 + (self.key[i] if c + self.key[i] + i//4 < 11000 else -self.key[i])))
|
|||
|
i += 1
|
|||
|
return Io.bytes(''.join(s))
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def encryptToFile(self, fromPath, toPath, i=0, event=None, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.ufile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath, False) as fo :
|
|||
|
s, lk = [], len(self.key)
|
|||
|
for c in Io.read_utf8_chr(fi):
|
|||
|
if i >= lk:
|
|||
|
i = 0
|
|||
|
if Sys.is_cli_cancel(event) :
|
|||
|
Sys.pwarn((('terminating child process ',(str(Sys.getpid()),Sys.CLZ_WARN_PARAM), ' !'),), False)
|
|||
|
break
|
|||
|
fo.write(chr(ord(c) + i//4 + (self.key[i] if ord(c) + self.key[i] + i//4 < 11000 else -self.key[i])))
|
|||
|
i += 1
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def decryptToFile(self, fromPath, toPath, i=0, event=None, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.ufile(fromPath) as fi :
|
|||
|
with Io.rfile(fromPath) as fi2 :
|
|||
|
s = fi2.read()
|
|||
|
with Io.wfile(toPath, False) as fo :
|
|||
|
s, lk = [], len(self.key)
|
|||
|
|
|||
|
for c in Io.read_utf8_chr(fi):
|
|||
|
if i >= lk:
|
|||
|
i = 0
|
|||
|
if Sys.is_cli_cancel(event) :
|
|||
|
Sys.pwarn((('terminating child process ',(str(Sys.getpid()),Sys.CLZ_WARN_PARAM), ' !'),), False)
|
|||
|
break
|
|||
|
try :
|
|||
|
fo.write(chr(ord(c)- i//4 + (-self.key[i] if ord(c) + self.key[i] +i//4 < 110000 else self.key[i])))
|
|||
|
except Exception as e :
|
|||
|
Sys.pwarn((('decryptToFile : ',(str(e),Sys.CLZ_ERROR_PARAM), ' !'),
|
|||
|
('ord c : ',(str(ord(c)),Sys.CLZ_ERROR_PARAM), ' - self.key[',(str(i),Sys.CLZ_ERROR_PARAM), '] : ',(str(self.key[i]),Sys.CLZ_ERROR_PARAM)),
|
|||
|
), True)
|
|||
|
raise e
|
|||
|
i += 1
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def randomFileContent(self, fromPath, toPath, emit=True):
|
|||
|
""""""
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
fsize, chsize, size = Kirmah.getSizes(fromPath)
|
|||
|
lst, rest, data = Kirmah.getRandomListFromKey(self.ck.key, size), chsize - fsize%chsize, ['b']*size
|
|||
|
if rest == chsize : rest = 0
|
|||
|
for piece, i in Io.read_in_chunks(fi, chsize):
|
|||
|
fo.seek(lst[i]*chsize-(rest if lst[i] > lst[size-1] else 0))
|
|||
|
fo.write(piece[::-1])
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Random mode', d, c)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def unRandomFileContent(self, fromPath, toPath, emit=True):
|
|||
|
""""""
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
fsize, chsize, size = Kirmah.getSizes(fromPath)
|
|||
|
lst, rest, piece, data = Kirmah.getRandomListFromKey(self.ck.key, size), chsize - fsize%chsize, b'', []
|
|||
|
if rest == chsize : rest = 0
|
|||
|
for i, pos in enumerate(lst):
|
|||
|
dp = pos*chsize-(rest if pos >= lst[size-1] and pos!=0 else 0)
|
|||
|
if dp >= 0 : fi.seek(dp)
|
|||
|
piece = fi.read(chsize)
|
|||
|
if i == size-1 and rest > 0 :
|
|||
|
piece = piece[:-rest] if lst[i]==0 else piece[rest:]
|
|||
|
fo.write(piece[::-1])
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Random mode - inv', d, c)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def mixdata(self, fromPath, toPath, encryptNoise=False, label='kirmah', cpart=22, emit=True):
|
|||
|
""""""
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
hlst = self.ck.getHashList(label, cpart, False)
|
|||
|
hlst['data'] = sorted(hlst['data'], key=lambda hlst: hlst[0])
|
|||
|
size = Sys.getsize(fromPath)
|
|||
|
psize = ceil(size/cpart)
|
|||
|
cp = 0
|
|||
|
rsz = 0
|
|||
|
for row in hlst['data']: rsz += row[2]+row[3]
|
|||
|
with Io.rfile(fromPath) as fi:
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
bdata, adata = '', ''
|
|||
|
for row in hlst['data']:
|
|||
|
bdata, adata = self.ck.noiser.getNoise(row[2]), self.ck.noiser.getNoise(row[3])
|
|||
|
if encryptNoise :
|
|||
|
bdata, adata = self.encryptStr(bdata)[:row[2]], self.encryptStr(adata)[:row[3]]
|
|||
|
fi.seek(psize*row[5])
|
|||
|
fo.write(bdata[:row[2]] + fi.read(psize) + adata[:row[3]])
|
|||
|
cp += 1
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Mix mode', d, c)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getNoiseLenBeforeIndex(self, hlst, psize, rest, size):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
lst, l, df, sou, f = [], 0, psize, False, 0
|
|||
|
lst.append(l)
|
|||
|
mxp = size // psize
|
|||
|
if size % psize == 0 : mxp -= 1
|
|||
|
for row in hlst:
|
|||
|
if row[5] == mxp :
|
|||
|
df = rest
|
|||
|
elif row[5] > mxp :
|
|||
|
df = 0
|
|||
|
else : df = psize
|
|||
|
l += row[2]+ row[3] + df
|
|||
|
lst.append(l)
|
|||
|
return lst
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def unmixdata(self, fromPath, toPath, label='kirmah', cpart=22, emit=True):
|
|||
|
""""""
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
rsz, cp, hlst = 0, 0, self.ck.getHashList(label, cpart, True)
|
|||
|
for row in hlst['data']:
|
|||
|
rsz += row[2]+row[3]
|
|||
|
size = Sys.getsize(fromPath)-rsz
|
|||
|
psize = ceil(size/cpart)
|
|||
|
rest = size % psize
|
|||
|
if rest == 0 : rest = psize
|
|||
|
lbi = self.getNoiseLenBeforeIndex(hlst['data'],psize,rest, size)
|
|||
|
hlst['data'] = sorted(hlst['data'], key=lambda hlst: hlst[5])
|
|||
|
mxp = size // psize
|
|||
|
if size % psize == 0 : mxp -= 1
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
with Io.wfile(toPath) as fo :
|
|||
|
header = fi.read(self.kh.POS_END)
|
|||
|
fi.seek(0,Io.SEEK_CUR)
|
|||
|
for row in hlst['data']:
|
|||
|
fi.seek(lbi[row[0]]+row[2])
|
|||
|
dp = fi.read(psize if row[5] <= mxp else (rest if rest!=psize or (psize*cpart==size) else 0))
|
|||
|
cp += 1
|
|||
|
if fo.tell() + len(dp) > size :
|
|||
|
fo.write(dp[:rest])
|
|||
|
break
|
|||
|
fo.write(dp)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Mix mode - inv', d, c)
|
|||
|
|
|||
|
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
# # SPLIT # #
|
|||
|
|
|||
|
@Log()
|
|||
|
def splitFile(self, fromPath, hlst, nproc=1):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
d = Sys.datetime.now()
|
|||
|
Sys.cli_emit_progress(2)
|
|||
|
self.split(fromPath, hlst)
|
|||
|
Sys.cli_emit_progress(70)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Splitting file', d, True)
|
|||
|
return self.kcfEnc(hlst)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def kcfEnc(self, hlst, nproc=1):
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
d = Sys.datetime.now()
|
|||
|
theStr = {'name': hlst['head'][0], 'count': hlst['head'][1] }
|
|||
|
Io.set_data(self.DIR_DEPLOY+hlst['head'][2]+'.tmp', str(theStr))
|
|||
|
self.encrypt(self.DIR_DEPLOY+hlst['head'][2]+'.tmp', self.DIR_DEPLOY+hlst['head'][2]+'.kcf', nproc, KirmahHeader(self.VERSION, Io.bytes(self.mark), KirmahHeader.COMP_NONE, True, True), False)
|
|||
|
Sys.removeFile(self.DIR_DEPLOY+hlst['head'][2]+'.tmp')
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
Sys.pstep('Encrypting Kirmah configuration file', d, True)
|
|||
|
Sys.cli_emit_progress(75)
|
|||
|
return self.DIR_DEPLOY+hlst['head'][2]+'.kcf'
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def split(self, fromPath, hlst):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
f = open(fromPath, 'rb+')
|
|||
|
m, p, rsz = mmap(f.fileno(), 0), 0, 0
|
|||
|
fsize = Sys.getsize(fromPath)
|
|||
|
Sys.cli_emit_progress(3)
|
|||
|
for row in hlst['data']: rsz += row[2]+row[3]
|
|||
|
# ensure correct order
|
|||
|
hlst['data'] = sorted(hlst['data'], key=lambda lst: lst[0])
|
|||
|
|
|||
|
self.splheader = self.kh.buildHeader(fsize)
|
|||
|
psize = ceil(fsize/hlst['head'][1])
|
|||
|
Sys.cli_emit_progress(4)
|
|||
|
perc = 5
|
|||
|
frav = 1.40
|
|||
|
while m.tell() < m.size():
|
|||
|
perc += frav
|
|||
|
Sys.cli_emit_progress(perc)
|
|||
|
self.splitPart(m, psize, hlst['data'][p])
|
|||
|
perc += frav
|
|||
|
Sys.cli_emit_progress(perc)
|
|||
|
p += 1
|
|||
|
m.close()
|
|||
|
|
|||
|
# ensure random order
|
|||
|
hlst['data'] = sorted(hlst['data'], key=lambda lst: lst[4])
|
|||
|
hlst['head'].append(psize)
|
|||
|
return hlst
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def splitPart(self, mmap, size, phlst):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.wfile(self.DIR_OUTBOX+phlst[1]+self.EXT) as fo :
|
|||
|
bdata, adata, part = self.ck.noiser.getNoise(phlst[2], False)[len(self.splheader):], self.ck.noiser.getNoise(phlst[3], False), int(phlst[0])
|
|||
|
zd = Io.gzcompress(bdata+mmap.read(size)+adata)
|
|||
|
hz = Io.bytes(self.offuscate(zd[:self.kh.POS_END], part))
|
|||
|
lhz = Io.bytes(str(part + len(hz)).rjust(3,'0'))
|
|||
|
fo.write(self.splheader+lhz+hz+zd[self.kh.POS_END:])
|
|||
|
|
|||
|
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
# # MERGE # #
|
|||
|
|
|||
|
@Log()
|
|||
|
def mergeFile(self, fromPath, toPath=None, uid=''):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
Sys.cli_emit_progress(2)
|
|||
|
self.decrypt(fromPath, '.cfg')
|
|||
|
Sys.cli_emit_progress(5)
|
|||
|
data = Io.get_data('.cfg')
|
|||
|
clist = literal_eval(data)
|
|||
|
Sys.removeFile('.cfg')
|
|||
|
theList = self.ck.getHashList(clist['name'], clist['count'], True)
|
|||
|
ext = ''
|
|||
|
if toPath is None :
|
|||
|
toPath = clist['name']
|
|||
|
elif Sys.isdir(toPath) :
|
|||
|
toPath += clist['name']
|
|||
|
toPath, ext = Sys.getFileExt(toPath)
|
|||
|
dirs = (Sys.dirname(Sys.realpath(toPath)) if toPath is not None else Sys.dirname(Sys.realpath(fromPath)))+Sys.sep
|
|||
|
Sys.cli_emit_progress(10)
|
|||
|
toPath = self.merge(theList, toPath, ext, uid, dirs)
|
|||
|
Sys.removeFile(fromPath)
|
|||
|
Sys.cli_emit_progress(90)
|
|||
|
return toPath
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def merge(self, hlst, fileName, ext='', uid='', dirs=None, fake=False):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
p = 0
|
|||
|
# ensure correct order
|
|||
|
hlst['data'] = sorted(hlst['data'], key=lambda lst: lst[0])
|
|||
|
#~ print(hlst['head'])
|
|||
|
#~ for row in hlst['data']:
|
|||
|
#~ print(row)
|
|||
|
#~ if dirs is not None and dirs!='none' :
|
|||
|
#~ dirPath = Sys.join(self.DIR_DEPLOY,dirs)+Sys.sep
|
|||
|
#~ Sys.mkdir_p(dirPath)
|
|||
|
#~ else: dirPath = self.DIR_DEPLOY
|
|||
|
#~ print('dirPath')
|
|||
|
#~ print(dirPath)
|
|||
|
#~ filePath = dirPath+fileName
|
|||
|
filePath = fileName
|
|||
|
if Io.file_exists(filePath+ext):
|
|||
|
filePath += '-'+str(uid)
|
|||
|
filePath += ext
|
|||
|
depDir = dirs
|
|||
|
perc = 10
|
|||
|
frav = len(hlst['data'])
|
|||
|
with Io.wfile(filePath) as fo :
|
|||
|
while p < hlst['head'][1] :
|
|||
|
perc = p/3*100/len(hlst['data'])
|
|||
|
Sys.cli_emit_progress(perc)
|
|||
|
try:
|
|||
|
self.mergePart(fo, hlst['data'][p], depDir)
|
|||
|
except Exception as e:
|
|||
|
Sys.pwarn((('merge : ',(str(e),Sys.CLZ_WARN_PARAM), ' !'),), True)
|
|||
|
raise e
|
|||
|
perc = p*100/len(hlst['data'])
|
|||
|
Sys.cli_emit_progress(perc)
|
|||
|
p += 1
|
|||
|
return filePath
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def mergePart(self, fo, phlst, depDir):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.rfile(depDir+phlst[1]+self.EXT) as fi:
|
|||
|
part, head = int(phlst[0]), fi.read(self.kh.POS_END)
|
|||
|
fo.write(Io.gzdecompress(self.deoffuscate(Io.str(fi.read(int(fi.read(3))-part)), part) + fi.read())[phlst[2]-self.kh.POS_END:-phlst[3]])
|
|||
|
Sys.removeFile(depDir+phlst[1]+self.EXT)
|
|||
|
|
|||
|
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
# # ENCRYPT # #
|
|||
|
|
|||
|
@Log()
|
|||
|
def mpMergeFiles(self,hlstPaths, toPath, noRemove=False, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
with Io.wfile(toPath) as fo:
|
|||
|
for fromPath in hlstPaths :
|
|||
|
with Io.rfile(fromPath) as fi :
|
|||
|
fo.write(fi.read())
|
|||
|
if not noRemove : Sys.removeFile(fromPath)
|
|||
|
#~ if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
#~ Sys.pstep('Encrypt Data (multiprocessing)', d, c)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def encrypt_sp_start(self, fromPath, toPath, header=None, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
if header is not None :
|
|||
|
self.kh = header
|
|||
|
fsize = Sys.getsize(fromPath)
|
|||
|
if fsize > 0 :
|
|||
|
strh = self.kh.buildHeader(fsize)
|
|||
|
decHeader = self.kh.readHeader(strh)
|
|||
|
self.tmpPath1 = self.DIR_TEMP + Sys.basename(fromPath) + '.tmp'
|
|||
|
self.tmpPath2 = self.DIR_TEMP + Sys.basename(fromPath) + '.tmp2'
|
|||
|
compend, compstart = not decHeader['cmode']== KirmahHeader.COMP_NONE, decHeader['cmode']== KirmahHeader.COMP_ALL
|
|||
|
fp, tp = fromPath, self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(2)
|
|||
|
d = Sys.datetime.now()
|
|||
|
if compstart :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Compressing data')
|
|||
|
self.compress_start(fp, tp, compstart, emit=emit)
|
|||
|
if compstart :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Compression mode', d, True)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(5)
|
|||
|
return fp, tp, decHeader['rmode'], decHeader['mmode'], compend
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def encrypt_sp_end(self, fp, tp, toPath, rmode, mmode, compend, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
if rmode :
|
|||
|
#~ self.mpRandomFileContent(fp, tp, 4)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Randomizing data')
|
|||
|
self.randomFileContent(fp, tp, emit=emit)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(75)
|
|||
|
|
|||
|
if mmode :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Mixing data')
|
|||
|
self.mixdata(fp, tp, True, emit=emit)
|
|||
|
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(85)
|
|||
|
|
|||
|
if compend :
|
|||
|
d = Sys.datetime.now()
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Compressing data')
|
|||
|
self.compress_end(fp, toPath, compend, emit=emit)
|
|||
|
if emit : Sys.cli_emit_progress(95)
|
|||
|
|
|||
|
if compend :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Compression mode', d, True)
|
|||
|
|
|||
|
# clean tmp files
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Cleaning')
|
|||
|
|
|||
|
try :
|
|||
|
Sys.removeFile(self.tmpPath1)
|
|||
|
Sys.removeFile(self.tmpPath2)
|
|||
|
except:
|
|||
|
pass
|
|||
|
if emit : Sys.cli_emit_progress(97)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def prepare_mproc_encode(self, fp, nproc):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
self.mproc_fsize = []
|
|||
|
fsize = Sys.getsize(fp)
|
|||
|
chsize = (fsize//nproc)+1
|
|||
|
if fsize % chsize == 0 : chsize -= 1
|
|||
|
|
|||
|
hlstPaths = []
|
|||
|
with Io.rfile(fp) as fi :
|
|||
|
for pdata, part in Io.read_in_chunks(fi, chsize):
|
|||
|
self.mproc_fsize.append(len(pdata))
|
|||
|
Io.set_data(self.KMP_FILE+'_'+str(Sys.getpid())+'_'+str(part), pdata, True)
|
|||
|
hlstPaths.append(self.KMP_FILE+'enc_'+str(Sys.getpid())+'_'+str(part))
|
|||
|
return hlstPaths
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def mproc_encode_part(self, id, event=None, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
mpfile, mpfilenc = self.KMP_FILE+'_'+str(Sys.g.MAIN_PROC)+'_'+str(id), self.KMP_FILE+'enc_'+str(Sys.g.MAIN_PROC)+'_'+str(id)
|
|||
|
self.encryptToFile(mpfile, mpfilenc, self.getSubStartIndice(id), event, emit=emit)
|
|||
|
Sys.removeFile(mpfile)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def encrypt_mproc(self, fp, tp, nproc=1, emit=True):
|
|||
|
""""""
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Encrypting data')
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
if nproc == 1 :
|
|||
|
self.encryptToFile(fp, tp)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Encrypt data', d, c)
|
|||
|
else :
|
|||
|
hlstPaths = self.prepare_mproc_encode(fp, nproc)
|
|||
|
mg = Manager(self.mproc_encode_part, nproc, None, Sys.g.MPEVENT)
|
|||
|
mg.run()
|
|||
|
self.mpMergeFiles(hlstPaths, tp, emit=emit)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Encrypt data (multiproc)', d, c)
|
|||
|
if emit : Sys.cli_emit_progress(70)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def encrypt(self, fromPath, toPath, nproc=1, header=None, emit=True):
|
|||
|
""""""
|
|||
|
if emit : Sys.cli_emit_progress(0)
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
fp, tp, rmode, mmode, compend = self.encrypt_sp_start(fromPath, toPath, header, emit=True)
|
|||
|
self.encrypt_mproc(fp, tp, nproc, emit=True)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
self.encrypt_sp_end(fp, tp, toPath, rmode, mmode, compend, emit=True)
|
|||
|
if emit : Sys.cli_emit_progress(100)
|
|||
|
|
|||
|
|
|||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|||
|
# # DECRYPT # #
|
|||
|
|
|||
|
@Log()
|
|||
|
def decrypt_sp_start(self, fromPath, toPath, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
if Sys.getsize(fromPath) > 0 :
|
|||
|
self.tmpPath1 = self.DIR_TEMP + Sys.basename(fromPath) + '.tmp'
|
|||
|
self.tmpPath2 = self.DIR_TEMP + Sys.basename(fromPath) + '.tmp2'
|
|||
|
fsize = Sys.getsize(fromPath)
|
|||
|
fsize -= self.kh.POS_END
|
|||
|
with Io.rfile(fromPath) as f :
|
|||
|
d = Sys.datetime.now()
|
|||
|
if emit : Sys.cli_emit_progress(1)
|
|||
|
decHeader = self.kh.readHeader(f.read(self.kh.POS_END))
|
|||
|
if emit : Sys.cli_emit_progress(2)
|
|||
|
#~ print(decHeader)
|
|||
|
if len(decHeader) > 0 :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if decHeader['smode'] == self.mark[fsize%len(self.mark)] :
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Reading Header', d, True)
|
|||
|
else :
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Reading Header', d, False, False, False)
|
|||
|
raise BadKeyException('wrong key')
|
|||
|
|
|||
|
compend, compstart = not decHeader['cmode']== KirmahHeader.COMP_NONE, decHeader['cmode']== KirmahHeader.COMP_ALL
|
|||
|
fp, tp = fromPath, self.tmpPath1
|
|||
|
|
|||
|
if emit : Sys.cli_emit_progress(3)
|
|||
|
if compend :
|
|||
|
d = Sys.datetime.now()
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Uncompressing data')
|
|||
|
self.uncompress_end(fp, tp, compend, emit=emit)
|
|||
|
if emit : Sys.cli_emit_progress(10)
|
|||
|
if compend :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Compression mode', d, True)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
|
|||
|
|
|||
|
if decHeader['mmode'] :
|
|||
|
d = Sys.datetime.now()
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Sorting data')
|
|||
|
self.unmixdata(fp, tp, emit=emit)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(20)
|
|||
|
if decHeader['rmode'] :
|
|||
|
d = Sys.datetime.now()
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Reordering data')
|
|||
|
self.unRandomFileContent(fp, tp, emit=emit)
|
|||
|
fp, tp = tp, self.tmpPath2 if tp == self.tmpPath1 else self.tmpPath1
|
|||
|
if emit : Sys.cli_emit_progress(25)
|
|||
|
return fp, tp, compstart
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def decrypt_sp_end(self, fromPath, toPath, compstart, emit=True):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
d = Sys.datetime.now()
|
|||
|
if emit : Sys.cli_emit_progress(80)
|
|||
|
if compstart :
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Uncompressing data')
|
|||
|
self.uncompress_start(fromPath, toPath, compstart, emit=emit)
|
|||
|
if emit : Sys.cli_emit_progress(90)
|
|||
|
if compstart:
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Compression mode', d, True)
|
|||
|
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Cleaning')
|
|||
|
if emit : Sys.cli_emit_progress(95)
|
|||
|
try :
|
|||
|
Sys.removeFile(self.tmpPath1)
|
|||
|
Sys.removeFile(self.tmpPath2)
|
|||
|
except:
|
|||
|
pass
|
|||
|
if emit : Sys.cli_emit_progress(97)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def decrypt_mproc(self, fromPath, toPath, nproc=1, emit=True):
|
|||
|
""""""
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.ptask('Decrypting data')
|
|||
|
d = Sys.datetime.now()
|
|||
|
c = not Sys.is_cli_cancel()
|
|||
|
if c:
|
|||
|
if emit : Sys.cli_emit_progress(30)
|
|||
|
if nproc == 1 :
|
|||
|
self.decryptToFile(fromPath, toPath)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Decrypt data', d, True)
|
|||
|
else :
|
|||
|
hlstPaths = self.prepare_mproc_decode(fromPath, nproc)
|
|||
|
mg = Manager(self.mproc_decode_part, nproc, None, Sys.g.MPEVENT, emit=True)
|
|||
|
mg.run()
|
|||
|
self.mpMergeFiles(hlstPaths, toPath, emit=emit)
|
|||
|
if Sys.g.DEBUG : Sys.wlog(Sys.dprint())
|
|||
|
if not Sys.g.QUIET : Sys.pstep('Decrypt data (multiproc)', d, True)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def prepare_mproc_decode(self, fp, nproc):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
self.mproc_fsize = []
|
|||
|
fsize = Sys.getsize(fp)
|
|||
|
chsize = (fsize//nproc)+1
|
|||
|
if fsize % chsize == 0 : chsize -= 1
|
|||
|
|
|||
|
hlstPaths = []
|
|||
|
with Io.rfile(fp) as fi :
|
|||
|
content = ''
|
|||
|
for pdata, part in Io.read_in_chunks(fi, chsize, True):
|
|||
|
content = Io.str(pdata)
|
|||
|
self.mproc_fsize.append(len(content))
|
|||
|
Io.set_data(self.KMP_FILE+'_'+str(Sys.getpid())+'_'+str(part), content)
|
|||
|
hlstPaths.append(self.KMP_FILE+'dec_'+str(Sys.getpid())+'_'+str(part))
|
|||
|
|
|||
|
return hlstPaths
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def mproc_decode_part(self, id, event=None, emit=True):
|
|||
|
""""""
|
|||
|
if emit : Sys.cli_emit_progress(-1)
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
mpfile, mpfiledec = self.KMP_FILE+'_'+str(Sys.g.MAIN_PROC)+'_'+str(id), self.KMP_FILE+'dec_'+str(Sys.g.MAIN_PROC)+'_'+str(id)
|
|||
|
self.decryptToFile(mpfile, mpfiledec, self.getSubStartIndice(id), event, emit=emit)
|
|||
|
Sys.removeFile(mpfile)
|
|||
|
|
|||
|
|
|||
|
@Log()
|
|||
|
def decrypt(self, fromPath, toPath, nproc=1, emit=True):
|
|||
|
""""""
|
|||
|
Sys.cli_emit_progress(0)
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
fp, tp, compstart = self.decrypt_sp_start(fromPath, toPath, emit=emit)
|
|||
|
self.decrypt_mproc(fp, tp, nproc, emit=emit)
|
|||
|
self.decrypt_sp_end(tp, toPath, compstart, emit=emit)
|
|||
|
|
|||
|
Sys.cli_emit_progress(100)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def offuscate(self, data, index):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
adata, lim = [], len(data)
|
|||
|
for i, c in enumerate((self.mark2)[index:]) :
|
|||
|
if i >= lim : break
|
|||
|
d = ord(c) + data[i]
|
|||
|
adata.append(chr(d))
|
|||
|
return ''.join(adata)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def deoffuscate(self, adata, index):
|
|||
|
""""""
|
|||
|
if not Sys.is_cli_cancel():
|
|||
|
data, lim = [], len(adata)
|
|||
|
for i, c in enumerate((self.mark2)[index:]) :
|
|||
|
if i >= lim : break
|
|||
|
d = ord(adata[i]) - ord(c)
|
|||
|
data.append(d)
|
|||
|
return bytes(bytearray(data))
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getSizes(fromPath):
|
|||
|
#~ if not Sys.is_cli_cancel():
|
|||
|
fsize = Sys.getsize(fromPath)
|
|||
|
s = (22,44,122,444,1222,14444,52222,244444,522222,1444444)
|
|||
|
a = (2,3,7,9,21,33,87,151,427)
|
|||
|
m, g = 4000, 3
|
|||
|
chsize = None
|
|||
|
if fsize <= 22 :
|
|||
|
chsize = ceil(fsize/4)+1
|
|||
|
else :
|
|||
|
for i, v in enumerate(s[:-1]) :
|
|||
|
if fsize >= v and fsize < s[i+1]:
|
|||
|
chsize = ceil(fsize/v)+a[i]
|
|||
|
break
|
|||
|
if chsize is None :
|
|||
|
chsize = ceil(fsize/1444444)+739
|
|||
|
if chsize == 0 : chsize = 1
|
|||
|
while ceil(fsize/chsize) > 4000 :
|
|||
|
chsize *= 3
|
|||
|
return fsize, chsize, ceil(fsize/chsize)
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log()
|
|||
|
def getRandomListFromKey(key, size):
|
|||
|
""""""
|
|||
|
#~ if not Sys.is_cli_cancel():
|
|||
|
j, ok, lk, r, ho, hr, lv, hv, rev = 0, False, len(key), None, [], [], 0, size-1, False
|
|||
|
for i in range(size) :
|
|||
|
if j >= lk : j = 0
|
|||
|
r = key[j]
|
|||
|
ok = r < size and not r in ho
|
|||
|
if not ok:
|
|||
|
r = hv if not rev else lv
|
|||
|
while r in ho :
|
|||
|
r = r - 1 if not rev else r + 1
|
|||
|
if r > size-1 : r = 0
|
|||
|
elif r < 0 : r = size - 1
|
|||
|
if not rev : hv = r
|
|||
|
else : lv = r
|
|||
|
ok = not r in ho
|
|||
|
if ok : ho.append(r)
|
|||
|
j += 1
|
|||
|
rev = not rev
|
|||
|
return Kirmah.getSimulRandomList(ho, Kirmah.getSimulNumber(key, size//5 if not size//5==0 else size*2, size//10 if not size//10 ==0 else size))
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getSimulRandomList(lst, chsize):
|
|||
|
""""""
|
|||
|
#~ if not Sys.is_cli_cancel():
|
|||
|
return Kirmah._getSimulRandomList(list(reversed(Kirmah._getSimulRandomList(Kirmah._getSimulRandomList(lst, chsize), 4))),4)
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log(Const.LOG_PRIVATE)
|
|||
|
def _getSimulRandomList(lst, chsize):
|
|||
|
""""""
|
|||
|
#~ if not Sys.is_cli_cancel():
|
|||
|
size, rlst, pos = len(lst), [], 0
|
|||
|
if chsize > 0 :
|
|||
|
for i in range(chsize+1):
|
|||
|
for j in range(ceil(size/chsize)+1):
|
|||
|
pos = j*chsize+i
|
|||
|
if pos in lst and not lst[pos] in rlst:
|
|||
|
rlst.append(lst[pos])
|
|||
|
else : rlst = lst
|
|||
|
return rlst
|
|||
|
|
|||
|
|
|||
|
@staticmethod
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getSimulNumber(key, lim, delta=12):
|
|||
|
""""""
|
|||
|
#~ if not Sys.is_cli_cancel():
|
|||
|
s = 0
|
|||
|
for c in key[::-1] :
|
|||
|
if represents_int(chr(c)): c = int(chr(c))
|
|||
|
if c > 2 and (lim-delta > c + s or c + s < lim + delta ) :
|
|||
|
s += c
|
|||
|
return s
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getSubStartIndice(self, idx):
|
|||
|
""""""
|
|||
|
return sum([ s for j, s in enumerate(self.mproc_fsize) if j < idx ])%len(self.key)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class Randomiz ~~
|
|||
|
|
|||
|
class Randomiz:
|
|||
|
""""""
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self,count,chl=None):
|
|||
|
""""""
|
|||
|
if chl ==None : self.lst = list(range(0,count))
|
|||
|
else: self.lst = chl
|
|||
|
self.count = len(self.lst)
|
|||
|
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def new(self,count=None, chl=None):
|
|||
|
""""""
|
|||
|
if count : self.count = count
|
|||
|
self.__init__(self.count,chl)
|
|||
|
|
|||
|
|
|||
|
def get(self,single=True):
|
|||
|
""""""
|
|||
|
pos = choice(self.lst)
|
|||
|
if single: del self.lst[self.lst.index(pos)]
|
|||
|
return pos
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class Noiser ~~
|
|||
|
|
|||
|
class Noiser:
|
|||
|
|
|||
|
@Log(Const.LOG_BUILD)
|
|||
|
def __init__(self, key, part=0):
|
|||
|
""""""
|
|||
|
self.key = key
|
|||
|
self.build(part)
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def build(self, part, vord=22):
|
|||
|
""""""
|
|||
|
if not part < len(self.key)-1 : raise Exception('part exceed limit')
|
|||
|
else :
|
|||
|
self.part, v = part, vord
|
|||
|
v = int(ceil((self.key[vord]+v)/4.20583))
|
|||
|
self.lns = abs(int(ceil(v/2))-self.key[self.part]+self.key[7])
|
|||
|
self.lne = abs(int(v-self.lns-self.key[self.part+2]-self.key[44]/2.1934))
|
|||
|
if self.lns < 24 : self.lns += 24
|
|||
|
if self.lne < 10 : self.lne += 10
|
|||
|
|
|||
|
@Log(Const.LOG_DEBUG)
|
|||
|
def getNoise(self, l, b64encode=True, noBytes=False):
|
|||
|
""""""
|
|||
|
n = urandom(l)
|
|||
|
if b64encode : n = urlsafe_b64encode(n)
|
|||
|
if noBytes:
|
|||
|
n = str(n,'utf-8')
|
|||
|
return n[:l]
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
# ~~ class BadKeyException ~~
|
|||
|
|
|||
|
class BadKeyException(BaseException):
|
|||
|
""""""
|