def decode(self, ciphertext): try: if self.cipher_mode == AES.MODE_EAX: cipher = AES.new(key=self.key, mode=self.cipher_mode, nonce=self.nonce) cipherbytes = b64decode(ciphertext.encode(self.text_encoding)) data = cipher.decrypt(cipherbytes) elif self.cipher_mode == AES.MODE_CBC: cipher = AES.new(key=self.key, mode=self.cipher_mode, iv=self.nonce) cipherbytes = b64decode(ciphertext.encode(self.text_encoding)) data = cipher.decrypt(cipherbytes) Log.debugdebug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Decrypted data length = ' + str(len(data)) + ', modulo 16 = ' + str(len(data) % 128 / 8)) # Remove last x bytes encoded in the padded bytes data = data[:-data[-1]] else: raise Exception( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Unsupported mode "' + str(self.cipher_mode) + '".') return str(data, encoding=STR_ENCODING) except Exception as ex: errmsg = str(__name__) + ' ' + str(getframeinfo(currentframe()).lineno) \ + ': Error decoding data "' + str(ciphertext) + '" using AES ". Exception: ' + str(ex) Log.error(errmsg) raise Exception(errmsg)
def hash_compression( self, s, # By default we return the original hash desired_byte_length = 32 ): if desired_byte_length % 4 != 0: raise Exception( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Desired byte length must be 0 modulo-4, given = ' + str(desired_byte_length) ) m = hashlib.sha256() m.update(bytes(s, encoding=Obfuscate.STRING_ENCODING)) # This will return a bytes list of length 32 h = m.digest() if len(h) % 4 != 0: raise Exception( str(__name__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Hash bytes length must be 0 modulo-4, got = ' + str(h) ) # We compress to 8 bytes from the 32 bytes # The original SHA-256 appends 8 parts concatenated together, we break into 4 parts and xor them # 4 blocks n_blocks = int( len(h) / desired_byte_length ) # 8 bytes block length block_len = int( len(h) / n_blocks ) Log.debugdebug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Number of blocks = ' + str(n_blocks) + ', block length = ' + str(block_len) ) # First block bytes_xor = h[0:block_len] for i in range(1, n_blocks, 1): idx_start = i * block_len idx_end = (i+1) * block_len cur_block = h[idx_start:idx_end] if len(bytes_xor) != len(cur_block): raise Exception( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Different block lengths "' + str(bytes_xor) + '", and "' + str(cur_block) + '"' ) bytes_xor = self.xor_bytes( b1 = bytes_xor, b2 = cur_block ) return bytes_xor
def encode( self, # bytes format data): try: if self.cipher_mode == AES.MODE_EAX: cipher = AES.new(key=self.key, mode=self.cipher_mode, nonce=self.nonce) cipherbytes, tag = cipher.encrypt_and_digest(data) return AES_Encrypt.EncryptRetClass( cipher_mode=self.cipher_mode_str, ciphertext_b64=b64encode(cipherbytes).decode( self.text_encoding), plaintext_b64=None, tag_b64=b64encode(tag).decode(self.text_encoding), nonce_b64=b64encode(self.nonce).decode(self.text_encoding)) elif self.cipher_mode == AES.MODE_CBC: # 1-16, make sure not 0, other wise last byte will not be block length length = AES_Encrypt.DEFAULT_BLOCK_SIZE_AES_CBC - ( len(data) % AES_Encrypt.DEFAULT_BLOCK_SIZE_AES_CBC) # Pad data with the original length, so when we decrypt we can just take data[-1] # as length of data block data += bytes(chr(length), encoding=STR_ENCODING) * length Log.debugdebug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Padded length = ' + str(length)) cipher = AES.new(key=self.key, mode=self.cipher_mode, iv=self.nonce) cipherbytes = cipher.encrypt(data) return AES_Encrypt.EncryptRetClass( cipher_mode=self.cipher_mode_str, ciphertext_b64=b64encode(cipherbytes).decode( self.text_encoding), plaintext_b64=None, tag_b64=None, nonce_b64=b64encode(self.nonce).decode(self.text_encoding)) else: raise Exception( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': Unsupported mode "' + str(self.cipher_mode) + '".') except Exception as ex: errmsg = str(__name__) + ' ' + str(getframeinfo(currentframe()).lineno) \ + ': Error encoding data "' + str(data) + '" using AES ". Exception: ' + str(ex) Log.error(errmsg) raise Exception(errmsg)
def convert_ascii_string_to_other_alphabet( ascii_char_string, # Default to CJK Unicode Block unicode_range=BLOCK_CHINESE, # If the characters come from a hexdigest from a hash, we can compress 4 times, # otherwise for a random ascii string, we can only compress 2 characters to 1 chinese. group_n_char=2): uni_len = unicode_range[1] - unicode_range[0] + 1 r = len(ascii_char_string) % 4 if r != 0: # Append 0's ascii_char_string = ascii_char_string + '0' * (4 - r) # raise Exception('Hash length ' + str(len(hash_hex_string)) # + ' for "' + str(hash_hex_string) + '" not 0 modulo-4') hash_zh = '' len_block = int(len(ascii_char_string) / group_n_char) for i in range(0, len_block, 1): idx_start = group_n_char * i idx_end = idx_start + group_n_char s = ascii_char_string[idx_start:idx_end] # Convert to Chinese, Korean, etc if group_n_char == 2: ord_arr = np.array([ord(x) for x in s]) val = ord_arr * np.array( [2**(8 * (x - 1)) for x in range(len(ord_arr), 0, -1)]) val = np.sum(val) Log.debug('Index start=' + str(idx_start) + ', end=' + str(idx_end) + ', s=' + str(s) + ', ordinal=' + str(ord_arr) + ', val=' + str(hex(val))) cjk_unicode = (val % uni_len) + unicode_range[0] hash_zh += chr(cjk_unicode) elif group_n_char == 4: Log.debug('Index start=' + str(idx_start) + ', end=' + str(idx_end) + ', s=' + str(s)) n = int('0x' + str(s), 16) cjk_unicode = (n % uni_len) + unicode_range[0] hash_zh += chr(cjk_unicode) Log.debugdebug('From ' + str(idx_start) + ': ' + str(s) + ', n=' + str(n) + ', char=' + str(chr(cjk_unicode))) return hash_zh
def xor_string( self, s1, s2 ): Log.debug( str(__name__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': XOR between "' + str(s1) + '" and "' + str(s2) + '".' ) len_s1 = len(s1) len_s2 = len(s2) len_max = max(len(s1), len(s2)) # Append to the shorter one, in a repeat manner for i in range(len(s1), len_max, 1): s1 += s1[(i-len_s1)] for i in range(len(s2), len_max, 1): s2 += s2[(i-len_s2)] Log.debug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': After appending, XOR between "' + str(s1) + '" and "' + str(s2) + '".' ) Log.debugdebug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': s1 "' + str(s1) + '", s2 "' + str(s2) + '"' ) b1 = bytes(s1, encoding=Obfuscate.STRING_ENCODING) b2 = bytes(s2, encoding=Obfuscate.STRING_ENCODING) bytes_xor = self.xor_bytes( b1 = b1, b2 = b2 ) return bytes_xor
def xor_bytes( self, b1, b2 ): t12 = zip(b1,b2) res_xor = [] for x in t12: byte_xor = x[0] ^ x[1] Log.debugdebug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + 'XOR "' + str(hex(x[0])) + '" and "' + str(hex(x[1])) + '" = ' + str(hex(byte_xor)) ) res_xor.append(byte_xor) Log.debug( str(self.__class__) + ' ' + str(getframeinfo(currentframe()).lineno) + ': XOR between "' + str(self.hexdigest(b1)) + '" and "' + str(self.hexdigest(b2)) + '" = "' + str(self.hexdigest(res_xor)) + '"' ) return res_xor