def _encrypt(self): """ Rebuild the master key from header settings and key-hash list. Encrypt the stream start bytes and the out-buffer formatted as hashed block stream with padding added as needed. """ # rebuild master key from (possibly) updated header self._make_master_key() # make hashed block stream block_buffer = HashedBlockIO() block_buffer.write(self.out_buffer.read()) # data is buffered in hashed block io, start a new one self.out_buffer = io.BytesIO() # write start bytes (for successful decrypt check) self.out_buffer.write(self.header.StreamStartBytes) # append blocked data to out-buffer block_buffer.write_block_stream(self.out_buffer) block_buffer.close() self.out_buffer.seek(0) # encrypt the whole thing with header settings and master key data = pad(self.out_buffer.read()) self.out_buffer = aes_cbc_encrypt(data, self.master_key, self.header.EncryptionIV)
def test_padding(): for size in range(8, 17): for str_len in range(0, 12): s = ''.join( [random.choice(string.printable) for _ in range(str_len)]) padded = pad(s, size=size) assert len(padded) % size == 0 unpadded = unpad(padded) assert unpadded == s
def get_pin(pinblock, accountNumber = None): # accountNumber must be printable string """ Get the pin associated with a pinblock adn an account number. :Parameters: - *pin\_block* (bytes array): The Pinblock. - *accountNumber* (string): The account number. :Returns: A string representing the pin. """ n = ord(pinblock[0]) & 0xf # low nibble defines pin len c = ord(pinblock[0]) >> 4 # high nibble defines pinblock format type if c in [0, 8]: # for pinblock format 0 (ansi pinblock 0) or 8 (null pinblock)... if accountNumber is None: pin = 'AccountNumber missing, it is mandatory for ' + str(c) + '-format' else: accountNumber = unhexlify(accountNumber.split('=', 1)[0][-13:-1]) # Remove check digit from Account Number, take the last 12 bytes and then unhexlify it accountNumber = crypto.pad(accountNumber, side = 'LEFT') # Padding Account Number pinblock = crypto.XOR(pinblock, accountNumber) # Remove accountNumber if c in [0, 1, 3]: # only for PinBlock with format type ANSI 0 / 1 / 3 if 4 <= n <= 12: pinBuffer = hexlify(pinblock) if c == 0: # only for PinBlock with format type ANSI 0 for s in pinBuffer[n+2:]: if s != 'f': pin = 'Wrong PIN Block of type 0' break else: pin = None if pin is None: pin = pinBuffer[2:n+2] try: int(pin) #check if pin contains only numbers except: pin = 'Wrong PIN Block Format' else: pin = 'Invalid digits number for PIN' elif c == 8: # only for PinBlock with format type Null PIN block if n == 0 and pinblock[-1:] == '\xff': pin = 'Null PIN Block' else: pin = 'Wrong Null PIN Block' else: pin = 'Wrong PIN Block Format' return str(pin)
def _decode(self, obj, context, path): decrypted_toc = aes_bom().decrypt(pad(obj))[:len(obj)] return Struct('entries' / ENTRY[context.n_entries], 'zlength' / GreedyRange(Int16ub)).parse(decrypted_toc)
def _encode(self, obj, context, path): data = Struct('entries' / ENTRY[context.n_entries], 'zlength' / GreedyRange(Int16ub)).build(obj) return aes_bom().encrypt(pad(data))[:len(data)]