def __transform_cbc(self, data): len_data = len(data) if len_data % 8: raise VCryptoException('Input not aligned to blocksize') result = [] start = 0 while start < len_data: end = start + 8 block = data[start:end] if self.__encrypt: if _pyver == 2: indata = b''.join([ _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(block, self.__iv) ]) else: indata = bytes([a ^ b for a, b in zip(block, self.__iv)]) cipher = self.__cipher.encipher(indata) self.__iv = cipher result.append(cipher) else: deciphered = self.__cipher.decipher(block) if _pyver == 2: plaintext = b''.join([ _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(deciphered, self.__iv) ]) else: plaintext = bytes( [a ^ b for a, b in zip(deciphered, self.__iv)]) self.__iv = block result.append(plaintext) start += 8 return b''.join(result)
def __transform_cbc(self, data): len_data = len(data) if len_data % self.__in_size: raise VCryptoException('Data not block aligned') result = [] start = 0 while start < len_data: end = start + self.__in_size block = data[start:end] if self.__encrypt: if _pyver == 2: indata = b''.join([ _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(block, self.__iv) ]) else: indata = bytes([a ^ b for a, b in zip(block, self.__iv)]) # Appending random data, similar to RSAES-PKCS1-V1_5-ENCRYPT _rand_data = self.__rand(8) indata = b''.join((b'\x02', indata, b'\x00', _rand_data)) cipher = self.__block_transform(indata, self.__in_size + 10, self.__out_size) # Can only take plaintext size bytes as the carry-on mask self.__iv = cipher[:(self.__plainsize)] result.append(cipher) else: deciphered = self.__block_transform(block, self.__in_size, self.__out_size + 10) if _pyver == 2: if deciphered[0] != b'\x02' or deciphered[-9] != b'\x00': raise VCryptoException('Invalid RSA ciphertext') else: if deciphered[0] != 0x02 or deciphered[-9] != 0x00: raise VCryptoException('Invalid RSA ciphertext') deciphered = deciphered[1:-8] if _pyver == 2: plaintext = b''.join([ _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(deciphered, self.__iv) ]) else: plaintext = bytes( [a ^ b for a, b in zip(deciphered, self.__iv)]) # Can only take plaintext size bytes as the carry-on mask self.__iv = block[:(self.__plainsize)] result.append(plaintext) start += self.__in_size return b''.join(result)
def data(self, num_bytes): l = [0] * num_bytes for gen in self.__generators: data = [_b_ord(c) for c in gen(num_bytes)] for i in xrange(len(l)): l[i] ^= data[i] return b''.join([_s2b(_b_chr(n)) for n in l])
def primedata_to_number(self, prime_data): """Returns a candidate prime number associated with byte data. :param prime_data: data which may represents a prime :type prime_data: bytes :returns: number associated with prime_data :rtype: int, long Sets the two most significant bits and the least significant bit of prime_data, before converting to an int or long. .. warning:: This method does not perform any type of primality check, and it is the responsibility of the caller to check whether the returned number represents a prime. """ bval = [_b_ord(c) for c in prime_data] bval[0] |= 0xc0 bval[-1] |= 0x01 if _pyver == 2: data = b''.join([_s2b(_b_chr(b)) for b in bval]) else: data = bytes(bval) return bytes_to_posint(data)
def message(self, plaintext): """Returns an encrypted message for a provided plaintext. :param plaintext: the plaintext to encode and encrypt :type plaintext: bytes :returns: encrypted message-protected plaintext :rtype: bytes :raises: :exc:`versile.crypto.VCryptoException` Raises an exception if provided plaintext is longer than :attr:`max_plaintext_len`\ , meaning the plaintext is larger than what is allowed inside a single message. Empty plaintext is also not allowed. """ plaintext_len = len(plaintext) if plaintext_len > self._max_plaintext_len: raise VCryptoException('Plaintext too long') elif not plaintext: raise VCryptoException('Empty plaintext not allowed') # Generate padding msg_len = 2 + plaintext_len + self._hash_len _bsize = self._plaintext_blocksize pad_len = msg_len % _bsize if pad_len: pad_len = _bsize - pad_len # Create message content encode_len = plaintext_len - 1 if _pyver == 2: plain_len = (_s2b(_b_chr((encode_len & 0xff00) >> 8)) + _s2b(_b_chr(encode_len & 0xff))) else: plain_len = bytes( (((encode_len & 0xff00) >> 8), (encode_len & 0xff))) padding = self._pad_provider(pad_len) _mac_msg = b''.join( (posint_to_bytes(self._msg_num), plain_len, plaintext, padding)) msg_hash = self._hash_cls.hmac(self._mac_secret, _mac_msg) msg = b''.join((plain_len, plaintext, padding, msg_hash)) # Create encrypted message enc_msg = self._encrypter(msg) self._msg_num += 1 return enc_msg
def hmac(cls, secret, message): """Generates and returns a :term:`HMAC` :param secret: secret key :type secret: bytes :param message: message :type message: bytes :returns: message authentication code :rtype: bytes Implements :term:`HMAC` algorithm defined by :rfc:`2104`\ . """ blocksize = cls.digest_size() if len(secret) > blocksize: secret = cls(secret).digest() elif len(secret) < blocksize: secret += (blocksize - len(secret)) * b'\x00' i_pad = blocksize * b'\x36' # TODO - TEMPORARY FIX FOR PYTHON 3 CONVERSION PROBLEM if _pyver == 3: inner = b''.join( _b_chr(_b_ord(a) ^ _b_ord(b)) for a, b in zip(secret, i_pad)) else: inner = b''.join( _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(secret, i_pad)) i_hash = cls(inner) i_hash.update(message) i_digest = i_hash.digest() o_pad = blocksize * b'\x5c' # TODO - TEMPORARY FIX FOR PYTHON 3 CONVERSION PROBLEM if _pyver == 3: outer = b''.join( _b_chr(_b_ord(a) ^ _b_ord(b)) for a, b in zip(secret, o_pad)) else: outer = b''.join( _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(secret, o_pad)) o_hash = cls(outer) o_hash.update(i_digest) return o_hash.digest()
def _increment(self, block): """Performs an increment of the previously generated block. :param block: input block :returns: output block Default is interpret the input block as an integer and to increment it by '1'. Derived classes can override to implement a different incrementation strategy. """ nums = [_b_ord(c) for c in block] for i in xrange((len(nums) - 1), -1, -1): if nums[i] == 255: nums[i] = 0 else: nums[i] += 1 break else: nums = [0] * len(nums) return b''.join([_s2b(_b_chr(n)) for n in nums])
def __transform_ofb(self, data): len_data = len(data) if len_data % 8: raise VCryptoException('Input not aligned to blocksize') result = [] start = 0 while start < len_data: end = start + 8 block = data[start:end] # Same for encryption/decryption mask = self.__cipher.encipher(self.__iv) self.__iv = mask if _pyver == 2: cipher = b''.join([ _s2b(_b_chr(_b_ord(a) ^ _b_ord(b))) for a, b in zip(block, mask) ]) else: cipher = bytes([a ^ b for a, b in zip(block, mask)]) result.append(cipher) start += 8 return b''.join(result)
def _decipher_block(self, block): if not isinstance(block, bytes) or len(block) != 8: raise VCryptoException('Data block must be bytes of len 8') b_l = ((_b_ord(block[0]) << 24) + (_b_ord(block[1]) << 16) + (_b_ord(block[2]) << 8) + _b_ord(block[3])) b_r = ((_b_ord(block[4]) << 24) + (_b_ord(block[5]) << 16) + (_b_ord(block[6]) << 8) + _b_ord(block[7])) P, S = self.__P, self.__S for i in xrange(17, 1, -1): b_l ^= P[i] b_r ^= self.__feistel(b_l) b_l, b_r = b_r, b_l b_l, b_r = b_r, b_l b_r ^= P[1] b_l ^= P[0] bval = [(b_l >> 24), (b_l >> 16), (b_l >> 8), b_l, (b_r >> 24), (b_r >> 16), (b_r >> 8), b_r] if _pyver == 2: return b''.join([_s2b(_b_chr(b & 0xff)) for b in bval]) else: return bytes([b & 0xff for b in bval])