Ejemplo n.º 1
0
    def rsassa_pkcs1_v1_5_verify(cls, key, hash_cls, msg, sig, crypto=None):
        """Verifies an RSSA-PKCS1-v1_5 Signature

        :param key:      public key for sign check
        :type  key:      :class:`versile.crypto.VAsymmetricKey`
        :param hash_cls: hash type for signature
        :type  hash_cls: :class:`versile.crypto.VHash`
        :param msg:      message to verify
        :type  msg:      bytes
        :param sig:      signature to verify against message
        :type  sig:      bytes
        :param crypto:   crypto provider (default if None)
        :type  crypto:   :class:`versile.crypto.VCrypto`
        :returns:        True if signature verifies
        :rtype:          bool

        Verifies a signature as defined by :term:`PKCS#1`\ .

        """
        crypto = VCrypto.lazy(crypto)
        enc_len = len(posint_to_bytes(key.keydata[0]))
        encoder = cls.emsa_pkcs1_v1_5_encode

        # Create digest and convert both sig and digest to integer format
        sig = bytes_to_posint(sig)
        digest = bytes_to_posint(encoder(msg, enc_len, hash_cls))

        # Decipher signature and compare with computed digest
        orig = crypto.num_cipher(key.cipher_name).encrypter(key)(sig)

        return (digest == orig)
Ejemplo n.º 2
0
 def __blocksize(self, max_num):
     """Compute block size from max number of a num cipher."""
     byte_rep = posint_to_bytes(max_num)
     c_blocksize = len(byte_rep)
     blocksize = c_blocksize - 11
     if blocksize <= 0:
         raise CryptoException('Supported block size must be minimum 1')
     return (blocksize, c_blocksize)
Ejemplo n.º 3
0
 def __block_transform(self, block, in_size, out_size):
     if len(block) != in_size:
         raise VCryptoException('Invalid input block size')
     num = bytes_to_posint(block)
     trans_num = self.__num_transform(num)
     trans_block = posint_to_bytes(trans_num)
     trans_block_len = len(trans_block)
     if trans_block_len > out_size:
         raise VCryptoException('Invalid output block size')
     elif trans_block_len < out_size:
         pad_num = out_size - trans_block_len
         trans_block = pad_num * b'\x00' + trans_block
     return trans_block
Ejemplo n.º 4
0
    def rsassa_pkcs1_v1_5_sign(cls, key, hash_cls, msg, crypto=None):
        """Sign message with a RSSA PKCS #1 v1.5 Signature

        :param key:      private key for signing
        :type  key:      :class:`versile.crypto.VAsymmetricKey`
        :param hash_cls: hash type for signature
        :type  hash_cls: :class:`versile.crypto.VHash`
        :param msg:      message to sign
        :type  msg:      bytes
        :param crypto:   crypto provider (default if None)
        :type  crypto:   :class:`versile.crypto.VCrypto`
        :raises:         :exc:`versile.crypto.VCryptoException`
        :returns:        signature
        :rtype:          bytes

        Produces a signature as defined by :term:`PKCS#1`\ . Raises an
        exception if a signature cannot be produced for the
        combination of the provided *key* and *hash_cls*\ .

        .. note::

            Signatures require using a hash method which has an associated
            registered :meth:`versile.crypto.VHash.oid`\ . Also, key length
            must be sufficient to hold signature data.

        """
        crypto = VCrypto.lazy(crypto)

        # Create a digest
        enc_len = len(posint_to_bytes(key.keydata[0]))
        encoder = cls.emsa_pkcs1_v1_5_encode
        digest = bytes_to_posint(encoder(msg, enc_len, hash_cls))

        # Create the signature
        sig = crypto.num_cipher(key.cipher_name).decrypter(key)(digest)
        sig = posint_to_bytes(sig)
        return sig
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
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