Beispiel #1
0
 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)
Beispiel #2
0
 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)
Beispiel #3
0
 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])
Beispiel #4
0
    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)
Beispiel #5
0
    def number(self, min_num, max_num):
        """Returns an integer constructed from generated byte data.

        :param min_num: lowest integer to produce
        :type  min_num: int, long
        :param max_num: highest integer to produce
        :type  max_num: int, long
        :returns:       number with min_num <= num <= max_num
        :rtype:         int, long

        The method will internally call :meth:`data` to generate data
        to create the output number.

        .. warning::

            The method may need to generate multiple iterations of
            byte data until a number can be constructed. If generated
            bytes do not appear 'random' (such as e.g. a constant byte
            value generator), this method may never return.

        """
        if min_num == max_num:
            return min_num
        diff = max_num - min_num
        diff_hex = _s2b(hex(diff)).lstrip(b'0x').rstrip(b'L')
        if len(diff_hex) % 2:
            diff_hex = b'0' + diff_hex
        num_bytes = len(diff_hex) // 2
        # Create a mask for the left zero bytes
        left_byte = int(_b2s(b'0x' + diff_hex[:2]), 16)
        mask = 0xff
        for i in xrange(7, -1, -1):
            bit = 0x01 << i
            if left_byte & bit:
                break
            else:
                mask = mask ^ bit
        while True:
            data = self(num_bytes)
            data_chars = [_s2b('0x')]
            first = True
            for d in data:
                b = _b_ord(d)
                if first:
                    b &= mask
                    first = False
                _chars = hex((b >> 4) & 0xf)[-1] + hex(b & 0xf)[-1]
                data_chars.append(_s2b(_chars))
            data_hex = _s2b('').join(data_chars)
            num = long(data_hex, 16)
            if num <= diff:
                break
        return min_num + num
Beispiel #6
0
 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)
Beispiel #7
0
    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()
Beispiel #8
0
    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])
Beispiel #9
0
    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])
Beispiel #10
0
    def read(self, data):
        """Reads encrypted message data.

        :param data: input data to decrypt and decode
        :type  data: bytes, :class:`versile.common.util.VByteBuffer`
        :returns:    number of bytes read
        :rtype:      int

        Reads only as much data as is required to complete processing
        a complete single message. If data is of type
        :class:`versile.common.util.VByteBuffer` then the data that
        was read will be popped off the buffer.

        .. note::

            When decryption of one message has completed,
            :meth:`reset` must be called before a new message can be
            read.

        """
        if isinstance(data, bytes):
            read_buf = self._read_buf
            read_buf.remove()
            read_buf.append(data)
        elif isinstance(data, VByteBuffer):
            read_buf = data
        else:
            raise TypeError('Input must be bytes or VByteBuffer')

        num_read = 0
        _pbsize = self._plaintext_blocksize
        _cbsize = self._cipher_blocksize
        while read_buf and self._result is None and not self._invalid:
            # First decode single block to get blocksize
            if not self._have_len:
                max_read = _cbsize - len(self._in_buf)
                enc_data = read_buf.pop(max_read)
                self._in_buf.append(enc_data)
                num_read += len(enc_data)
                if len(self._in_buf) == _cbsize:
                    enc_data = self._in_buf.pop()
                    block = self._decrypter(enc_data)
                    if _pbsize is None:
                        _pbsize = len(block)
                        self._plaintext_blocksize = _pbsize
                    self._msg_buf.append(block)
                    len_bytes = self._msg_buf.peek(2)
                    if _pyver == 2:
                        self._plaintext_len = 1 + (
                            (_b_ord(len_bytes[0]) << 8) + _b_ord(len_bytes[1]))
                    else:
                        self._plaintext_len = 1 + (
                            (len_bytes[0] << 8) + len_bytes[1])
                    self._have_len = True

            # If we have first block, decrypt more blocks as available/needed
            if self._have_len:
                msg_len = 2 + self._plaintext_len + self._hash_len
                pad_len = msg_len % _pbsize
                if pad_len:
                    pad_len = _pbsize - pad_len
                    msg_len += pad_len
                msg_left = msg_len - len(self._msg_buf)
                blocks_left = msg_left // _pbsize
                input_left = (blocks_left * _cbsize - len(self._in_buf))
                in_data = read_buf.pop(input_left)
                num_read += len(in_data)
                self._in_buf.append(in_data)
                num_decode = len(self._in_buf)
                num_decode -= num_decode % _cbsize
                if num_decode > 0:
                    enc_data = self._in_buf.pop(num_decode)
                    self._msg_buf.append(self._decrypter(enc_data))
                elif len(self._msg_buf) != msg_len:
                    break

            if self._have_len and len(self._msg_buf) == msg_len:
                len_bytes = self._msg_buf.pop(2)
                plaintext = self._msg_buf.pop(self._plaintext_len)
                padding = self._msg_buf.pop(pad_len)
                msg_hash = self._msg_buf.pop(self._hash_len)

                _mac_msg = b''.join((posint_to_bytes(self._msg_num), len_bytes,
                                     plaintext, padding))
                if msg_hash == self._hash_cls.hmac(self._mac_secret, _mac_msg):
                    self._result = plaintext
                    self._msg_num += 1
                else:
                    self._invalid = True

        return num_read
Beispiel #11
0
    def __init__(self, key):
        if not isinstance(key, bytes):
            raise VCryptoException('Key must be a bytes object')
        elif len(key) > 56:
            raise VCryptoException('Max key length is 448 bits (56 bytes)')

        P, S = copy.deepcopy(_P_INIT), copy.deepcopy(_S_INIT)
        self.__P, self.__S = P, S

        keylen = len(key)
        j = 0
        for i in xrange(len(P)):
            data = 0
            for k in xrange(4):
                data = ((data << 8) & 0xffffffff) | _b_ord(key[j])
                j += 1
                if j >= keylen:
                    j = 0
            P[i] ^= data

        data = 8 * b'\x00'
        for i in xrange(0, len(P), 2):
            data = self.encipher(data)
            P[i] = ((_b_ord(data[0]) << 24) + (_b_ord(data[1]) << 16) +
                    (_b_ord(data[2]) << 8) + _b_ord(data[3]))
            P[i + 1] = ((_b_ord(data[4]) << 24) + (_b_ord(data[5]) << 16) +
                        (_b_ord(data[6]) << 8) + _b_ord(data[7]))

        for i in xrange(4):
            for j in xrange(0, 256, 2):
                data = self.encipher(data)
                S[i][j] = ((_b_ord(data[0]) << 24) + (_b_ord(data[1]) << 16) +
                           (_b_ord(data[2]) << 8) + _b_ord(data[3]))
                S[i][j +
                     1] = ((_b_ord(data[4]) << 24) + (_b_ord(data[5]) << 16) +
                           (_b_ord(data[6]) << 8) + _b_ord(data[7]))