Example #1
0
def save_pem(contents, pem_marker):
    '''Saves a PEM file.

    @param contents: the contents to encode in PEM format
    @param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    @return the base64-encoded content between the start and end markers.

    '''

    (pem_start, pem_end) = _markers(pem_marker)

    b64 = base64.encodestring(contents).replace(b('\n'), b(''))
    pem_lines = [pem_start]

    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b(''))

    return b('\n').join(pem_lines)
Example #2
0
def _pad_for_signing(message, target_length):
    r'''Pads the message for signing, returning the padded message.
    
    The padding is always a repetition of FF bytes.
    
    :return: 00 01 PADDING 00 MESSAGE
    
    >>> block = _pad_for_signing('hello', 16)
    >>> len(block)
    16
    >>> block[0:2]
    '\x00\x01'
    >>> block[-6:]
    '\x00hello'
    >>> block[2:-6]
    '\xff\xff\xff\xff\xff\xff\xff\xff'
    
    '''

    max_msglength = target_length - 11
    msglength = len(message)

    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only'
                            ' space for %i' % (msglength, max_msglength))

    padding_length = target_length - msglength - 3

    return b('').join(
        [b('\x00\x01'), padding_length * b('\xff'),
         b('\x00'), message])
Example #3
0
def _pad_for_signing(message, target_length):
    r'''Pads the message for signing, returning the padded message.
    
    The padding is always a repetition of FF bytes.
    
    :return: 00 01 PADDING 00 MESSAGE
    
    >>> block = _pad_for_signing('hello', 16)
    >>> len(block)
    16
    >>> block[0:2]
    '\x00\x01'
    >>> block[-6:]
    '\x00hello'
    >>> block[2:-6]
    '\xff\xff\xff\xff\xff\xff\xff\xff'
    
    '''

    max_msglength = target_length - 11
    msglength = len(message)
    
    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only'
            ' space for %i' % (msglength, max_msglength))
    
    padding_length = target_length - msglength - 3
    
    return b('').join([b('\x00\x01'),
                    padding_length * b('\xff'),
                    b('\x00'),
                    message])
Example #4
0
def load_pem(contents, pem_marker):
    pem_start, pem_end = _markers(pem_marker)
    pem_lines = []
    in_pem_part = False
    for line in contents.splitlines():
        line = line.strip()
        if not line:
            continue
        if line == pem_start:
            if in_pem_part:
                raise ValueError('Seen start marker "%s" twice' % pem_start)
            in_pem_part = True
            continue
        if not in_pem_part:
            continue
        if in_pem_part and line == pem_end:
            in_pem_part = False
            break
        if b(':') in line:
            continue
        pem_lines.append(line)

    if not pem_lines:
        raise ValueError('No PEM start marker "%s" found' % pem_start)
    if in_pem_part:
        raise ValueError('No PEM end marker "%s" found' % pem_end)
    pem = b('').join(pem_lines)
    return base64.decodestring(pem)
Example #5
0
def load_pem(contents, pem_marker):
    """Loads a PEM file.

    :param contents: the contents of the file to interpret
    :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    :return: the base64-decoded content between the start and end markers.

    @raise ValueError: when the content is invalid, for example when the start
        marker cannot be found.

    """

    (pem_start, pem_end) = _markers(pem_marker)

    pem_lines = []
    in_pem_part = False

    for line in contents.splitlines():
        line = line.strip()

        # Skip empty lines
        if not line:
            continue

        # Handle start marker
        if line == pem_start:
            if in_pem_part:
                raise ValueError('Seen start marker "%s" twice' % pem_start)

            in_pem_part = True
            continue

        # Skip stuff before first marker
        if not in_pem_part:
            continue

        # Handle end marker
        if in_pem_part and line == pem_end:
            in_pem_part = False
            break

        # Load fields
        if b(':') in line:
            continue

        pem_lines.append(line)

    # Do some sanity checks
    if not pem_lines:
        raise ValueError('No PEM start marker "%s" found' % pem_start)

    if in_pem_part:
        raise ValueError('No PEM end marker "%s" found' % pem_end)

    # Base64-decode the contents
    pem = b('').join(pem_lines)
    return base64.standard_b64decode(pem)
Example #6
0
def save_pem(contents, pem_marker):
    """Saves a PEM file.

    :param contents: the contents to encode in PEM format
    :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    :return: the base64-encoded content between the start and end markers.

    """

    (pem_start, pem_end) = _markers(pem_marker)

    b64 = base64.standard_b64encode(contents).replace(b('\n'), b(''))
    pem_lines = [pem_start]

    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b(''))

    return b('\n').join(pem_lines)
Example #7
0
def load_pem(contents, pem_marker):
    '''Loads a PEM file.

    @param contents: the contents of the file to interpret
    @param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY'
        when your file has '-----BEGIN RSA PRIVATE KEY-----' and
        '-----END RSA PRIVATE KEY-----' markers.

    @return the base64-decoded content between the start and end markers.

    @raise ValueError: when the content is invalid, for example when the start
        marker cannot be found.

    '''

    (pem_start, pem_end) = _markers(pem_marker)

    pem_lines = []
    in_pem_part = False

    for line in contents.splitlines():
        line = line.strip()

        # Skip empty lines
        if not line:
            continue

        # Handle start marker
        if line == pem_start:
            if in_pem_part:
                raise ValueError('Seen start marker "%s" twice' % pem_start)

            in_pem_part = True
            continue

        # Skip stuff before first marker
        if not in_pem_part:
            continue

        # Handle end marker
        if in_pem_part and line == pem_end:
            in_pem_part = False
            break

        # Load fields
        if b(':') in line:
            continue

        pem_lines.append(line)

    # Do some sanity checks
    if not pem_lines:
        raise ValueError('No PEM start marker "%s" found' % pem_start)

    if in_pem_part:
        raise ValueError('No PEM end marker "%s" found' % pem_end)

    # Base64-decode the contents
    pem = b('').join(pem_lines)
    return base64.decodestring(pem)
Example #8
0
def load_pem(contents, pem_marker):
    pem_start, pem_end = _markers(pem_marker)
    pem_lines = []
    in_pem_part = False
    for line in contents.splitlines():
        line = line.strip()
        if not line:
            continue
        if line == pem_start:
            if in_pem_part:
                raise ValueError('Seen start marker "%s" twice' % pem_start)
            in_pem_part = True
            continue
        if not in_pem_part:
            continue
        if in_pem_part and line == pem_end:
            in_pem_part = False
            break
        if b(':') in line:
            continue
        pem_lines.append(line)

    if not pem_lines:
        raise ValueError('No PEM start marker "%s" found' % pem_start)
    if in_pem_part:
        raise ValueError('No PEM end marker "%s" found' % pem_end)
    pem = b('').join(pem_lines)
    return base64.decodestring(pem)
Example #9
0
    def test_chunk_size(self):
        self.assertEqual(int2bytes(123456789, 6), b('\x00\x00\x07[\xcd\x15'))
        self.assertEqual(int2bytes(123456789, 7),
                         b('\x00\x00\x00\x07[\xcd\x15'))

        self.assertEqual(_int2bytes(123456789, 6), b('\x00\x00\x07[\xcd\x15'))
        self.assertEqual(_int2bytes(123456789, 7),
                         b('\x00\x00\x00\x07[\xcd\x15'))
Example #10
0
def _markers(pem_marker):
    """
    Returns the start and end PEM markers
    """
    if is_bytes(pem_marker):
        pem_marker = pem_marker.decode('utf-8')
    return (b('-----BEGIN %s-----' % pem_marker),
            b('-----END %s-----' % pem_marker))
Example #11
0
    def test_chunk_size(self):
        self.assertEqual(int2bytes(123456789, 6), b('\x00\x00\x07[\xcd\x15'))
        self.assertEqual(int2bytes(123456789, 7),
                         b('\x00\x00\x00\x07[\xcd\x15'))

        self.assertEqual(_int2bytes(123456789, 6),
                         b('\x00\x00\x07[\xcd\x15'))
        self.assertEqual(_int2bytes(123456789, 7),
                         b('\x00\x00\x00\x07[\xcd\x15'))
Example #12
0
def _pad_for_signing(message, target_length):
    max_msglength = target_length - 11
    msglength = len(message)
    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only space for %i' % (msglength, max_msglength))
    padding_length = target_length - msglength - 3
    return b('').join([b('\x00\x01'),
     padding_length * b('\xff'),
     b('\x00'),
     message])
Example #13
0
def _markers(pem_marker):
    """
    Returns the start and end PEM markers
    """

    if is_bytes(pem_marker):
        pem_marker = pem_marker.decode('utf-8')

    return (b('-----BEGIN %s-----' % pem_marker),
            b('-----END %s-----' % pem_marker))
Example #14
0
def _markers(pem_marker):
    """
    Returns the start and end PEM markers, as bytes.
    """

    if not is_bytes(pem_marker):
        pem_marker = pem_marker.encode('ascii')

    return (b('-----BEGIN ') + pem_marker + b('-----'),
            b('-----END ') + pem_marker + b('-----'))
Example #15
0
    def test_keygen_priv_stdout(self):
        with captured_output() as (out, err):
            with cli_args(128):
                rsa.cli.keygen()

        lines = get_bytes_out(out).splitlines()
        self.assertEqual(b('-----BEGIN RSA PRIVATE KEY-----'), lines[0])
        self.assertEqual(b('-----END RSA PRIVATE KEY-----'), lines[-1])

        # The key size should be shown on stderr
        self.assertTrue('128-bit key' in err.getvalue())
Example #16
0
    def test_keygen_priv_stdout(self):
        with captured_output() as (out, err):
            with cli_args(128):
                rsa.cli.keygen()

        lines = get_bytes_out(out).splitlines()
        self.assertEqual(b('-----BEGIN RSA PRIVATE KEY-----'), lines[0])
        self.assertEqual(b('-----END RSA PRIVATE KEY-----'), lines[-1])

        # The key size should be shown on stderr
        self.assertTrue('128-bit key' in err.getvalue())
Example #17
0
def save_pem(contents, pem_marker):
    pem_start, pem_end = _markers(pem_marker)
    b64 = base64.encodestring(contents).replace(b('\n'), b(''))
    pem_lines = [pem_start]
    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b(''))
    return b('\n').join(pem_lines)
Example #18
0
def _pad_for_signing(message, target_length):
    max_msglength = target_length - 11
    msglength = len(message)
    if msglength > max_msglength:
        raise OverflowError(
            '%i bytes needed for message, but there is only space for %i' %
            (msglength, max_msglength))
    padding_length = target_length - msglength - 3
    return b('').join(
        [b('\x00\x01'), padding_length * b('\xff'),
         b('\x00'), message])
Example #19
0
def save_pem(contents, pem_marker):
    pem_start, pem_end = _markers(pem_marker)
    b64 = base64.encodestring(contents).replace(b('\n'), b(''))
    pem_lines = [pem_start]
    for block_start in range(0, len(b64), 64):
        block = b64[block_start:block_start + 64]
        pem_lines.append(block)

    pem_lines.append(pem_end)
    pem_lines.append(b(''))
    return b('\n').join(pem_lines)
Example #20
0
    def test_read_zero(self):
        encoded = b('\x00crummy')
        infile = BytesIO(encoded)

        (decoded, read) = varblock.read_varint(infile)

        # Test the returned values
        self.assertEqual(0, decoded)
        self.assertEqual(1, read)

        # The rest of the file should be untouched
        self.assertEqual(b('crummy'), infile.read())
    def test_read_zero(self):
        encoded = b('\x00crummy')
        infile = BytesIO(encoded)

        (decoded, read) = varblock.read_varint(infile)

        # Test the returned values
        self.assertEqual(0, decoded)
        self.assertEqual(1, read)

        # The rest of the file should be untouched
        self.assertEqual(b('crummy'), infile.read())
Example #22
0
def decrypt(crypto, priv_key):
    blocksize = common.byte_size(priv_key.n)
    encrypted = transform.bytes2int(crypto)
    decrypted = core.decrypt_int(encrypted, priv_key.d, priv_key.n)
    cleartext = transform.int2bytes(decrypted, blocksize)
    if cleartext[0:2] != b('\x00\x02'):
        raise DecryptionError('Decryption failed')
    try:
        sep_idx = cleartext.index(b('\x00'), 2)
    except ValueError:
        raise DecryptionError('Decryption failed')

    return cleartext[sep_idx + 1:]
Example #23
0
def decrypt(crypto, priv_key):
    blocksize = common.byte_size(priv_key.n)
    encrypted = transform.bytes2int(crypto)
    decrypted = core.decrypt_int(encrypted, priv_key.d, priv_key.n)
    cleartext = transform.int2bytes(decrypted, blocksize)
    if cleartext[0:2] != b('\x00\x02'):
        raise DecryptionError('Decryption failed')
    try:
        sep_idx = cleartext.index(b('\x00'), 2)
    except ValueError:
        raise DecryptionError('Decryption failed')

    return cleartext[sep_idx + 1:]
Example #24
0
    def test_sign_verify_bigfile(self):
        # Large enough to store MD5-sum and ASN.1 code for MD5
        pub_key, priv_key = rsa.newkeys((34 + 11) * 8)

        # Sign the file
        msgfile = BytesIO(b("123456Sybren"))
        signature = pkcs1.sign(msgfile, priv_key, "MD5")

        # Check the signature
        msgfile.seek(0)
        self.assertTrue(pkcs1.verify(msgfile, signature, pub_key))

        # Alter the message, re-check
        msgfile = BytesIO(b("123456sybren"))
        self.assertRaises(pkcs1.VerificationError, pkcs1.verify, msgfile, signature, pub_key)
Example #25
0
def verify(message, signature, pub_key):
    blocksize = common.byte_size(pub_key.n)
    encrypted = transform.bytes2int(signature)
    decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
    clearsig = transform.int2bytes(decrypted, blocksize)
    if clearsig[0:2] != b('\x00\x01'):
        raise VerificationError('Verification failed')
    try:
        sep_idx = clearsig.index(b('\x00'), 2)
    except ValueError:
        raise VerificationError('Verification failed')

    method_name, signature_hash = _find_method_hash(clearsig[sep_idx + 1:])
    message_hash = _hash(message, method_name)
    if message_hash != signature_hash:
        raise VerificationError('Verification failed')
    def test_write_zero(self):
        outfile = BytesIO()
        written = varblock.write_varint(outfile, 0)

        # Test the returned values
        self.assertEqual(b('\x00'), outfile.getvalue())
        self.assertEqual(1, written)
Example #27
0
    def test_write_zero(self):
        outfile = BytesIO()
        written = varblock.write_varint(outfile, 0)

        # Test the returned values
        self.assertEqual(b('\x00'), outfile.getvalue())
        self.assertEqual(1, written)
Example #28
0
    def test_encrypt_decrypt_bigfile(self):
        # Expected block size + 11 bytes padding
        pub_key, priv_key = rsa.newkeys((6 + 11) * 8)

        # Encrypt the file
        message = b('123456Sybren')
        infile = BytesIO(message)
        outfile = BytesIO()

        bigfile.encrypt_bigfile(infile, outfile, pub_key)

        # Test
        crypto = outfile.getvalue()

        cryptfile = BytesIO(crypto)
        clearfile = BytesIO()

        bigfile.decrypt_bigfile(cryptfile, clearfile, priv_key)
        self.assertEquals(clearfile.getvalue(), message)

        # We have 2x6 bytes in the message, so that should result in two
        # bigfile.
        cryptfile.seek(0)
        varblocks = list(varblock.yield_varblocks(cryptfile))
        self.assertEqual(2, len(varblocks))
Example #29
0
def int2bytes(number, fill_size=None, chunk_size=None, overflow=False):
    if number < 0:
        raise ValueError('Number must be an unsigned integer: %d' % number)
    if fill_size and chunk_size:
        raise ValueError('You can either fill or pad chunks, but not both')
    number & 1
    raw_bytes = b('')
    num = number
    word_bits, _, max_uint, pack_type = get_word_alignment(num)
    pack_format = '>%s' % pack_type
    while num > 0:
        raw_bytes = pack(pack_format, num & max_uint) + raw_bytes
        num >>= word_bits

    zero_leading = bytes_leading(raw_bytes)
    if number == 0:
        raw_bytes = ZERO_BYTE
    raw_bytes = raw_bytes[zero_leading:]
    length = len(raw_bytes)
    if fill_size and fill_size > 0:
        if not overflow and length > fill_size:
            raise OverflowError(
                'Need %d bytes for number, but fill size is %d' %
                (length, fill_size))
        raw_bytes = raw_bytes.rjust(fill_size, ZERO_BYTE)
    elif chunk_size and chunk_size > 0:
        remainder = length % chunk_size
        if remainder:
            padding_size = chunk_size - remainder
            raw_bytes = raw_bytes.rjust(length + padding_size, ZERO_BYTE)
    return raw_bytes
    def test_encrypt_decrypt_bigfile(self):
        # Expected block size + 11 bytes padding
        pub_key, priv_key = rsa.newkeys((6 + 11) * 8)

        # Encrypt the file
        message = b('123456Sybren')
        infile = BytesIO(message)
        outfile = BytesIO()

        bigfile.encrypt_bigfile(infile, outfile, pub_key)

        # Test
        crypto = outfile.getvalue()

        cryptfile = BytesIO(crypto)
        clearfile = BytesIO()

        bigfile.decrypt_bigfile(cryptfile, clearfile, priv_key)
        self.assertEquals(clearfile.getvalue(), message)

        # We have 2x6 bytes in the message, so that should result in two
        # bigfile.
        cryptfile.seek(0)
        varblocks = list(varblock.yield_varblocks(cryptfile))
        self.assertEqual(2, len(varblocks))
Example #31
0
 def _save_pkcs1_pem(self):
     """Saves a PKCS#1 PEM-encoded private key file.
     
     @return: contents of a PEM-encoded file that contains the private key.
     """
     der = self._save_pkcs1_der()
     return rsa.pem.save_pem(der, b('RSA PRIVATE KEY'))
    def test_sign_verify_bigfile(self):
        # Large enough to store MD5-sum and ASN.1 code for MD5
        pub_key, priv_key = rsa.newkeys((34 + 11) * 8)

        # Sign the file
        msgfile = BytesIO(b('123456Sybren'))
        signature = pkcs1.sign(msgfile, priv_key, 'MD5')

        # Check the signature
        msgfile.seek(0)
        self.assertTrue(pkcs1.verify(msgfile, signature, pub_key))

        # Alter the message, re-check
        msgfile = BytesIO(b('123456sybren'))
        self.assertRaises(pkcs1.VerificationError, pkcs1.verify, msgfile,
                          signature, pub_key)
Example #33
0
def verify(message, signature, pub_key):
    blocksize = common.byte_size(pub_key.n)
    encrypted = transform.bytes2int(signature)
    decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
    clearsig = transform.int2bytes(decrypted, blocksize)
    if clearsig[0:2] != b('\x00\x01'):
        raise VerificationError('Verification failed')
    try:
        sep_idx = clearsig.index(b('\x00'), 2)
    except ValueError:
        raise VerificationError('Verification failed')

    method_name, signature_hash = _find_method_hash(clearsig[sep_idx + 1:])
    message_hash = _hash(message, method_name)
    if message_hash != signature_hash:
        raise VerificationError('Verification failed')
Example #34
0
def verify(message, signature, pub_key):
    '''Verifies that the signature matches the message.
    
    The hash method is detected automatically from the signature.
    
    :param message: the signed message. Can be an 8-bit string or a file-like
        object. If ``message`` has a ``read()`` method, it is assumed to be a
        file-like object.
    :param signature: the signature block, as created with :py:func:`rsa.sign`.
    :param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message.
    :raise VerificationError: when the signature doesn't match the message.

    .. warning::

        Never display the stack trace of a
        :py:class:`rsa.pkcs1.VerificationError` exception. It shows where in
        the code the exception occurred, and thus leaks information about the
        key. It's only a tiny bit of information, but every bit makes cracking
        the keys easier.

    '''

    blocksize = common.byte_size(pub_key.n)
    encrypted = transform.bytes2int(signature)
    decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
    clearsig = transform.int2bytes(decrypted, blocksize)

    # If we can't find the signature  marker, verification failed.
    if clearsig[0:2] != b('\x00\x01'):
        raise VerificationError('Verification failed')

    # Find the 00 separator between the padding and the payload
    try:
        sep_idx = clearsig.index(b('\x00'), 2)
    except ValueError:
        raise VerificationError('Verification failed')

    # Get the hash and the hash method
    (method_name, signature_hash) = _find_method_hash(clearsig[sep_idx + 1:])
    message_hash = _hash(message, method_name)

    # Compare the real hash to the hash in the signature
    if message_hash != signature_hash:
        raise VerificationError('Verification failed')

    return True
Example #35
0
    def _save_pkcs1_pem(self):
        '''Saves a PKCS#1 PEM-encoded private key file.

        @return: contents of a PEM-encoded file that contains the private key.
        '''

        der = self._save_pkcs1_der()
        return rsa.pem.save_pem(der, b('RSA PRIVATE KEY'))
Example #36
0
def verify(message, signature, pub_key):
    '''Verifies that the signature matches the message.
    
    The hash method is detected automatically from the signature.
    
    :param message: the signed message. Can be an 8-bit string or a file-like
        object. If ``message`` has a ``read()`` method, it is assumed to be a
        file-like object.
    :param signature: the signature block, as created with :py:func:`rsa.sign`.
    :param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message.
    :raise VerificationError: when the signature doesn't match the message.

    .. warning::

        Never display the stack trace of a
        :py:class:`rsa.pkcs1.VerificationError` exception. It shows where in
        the code the exception occurred, and thus leaks information about the
        key. It's only a tiny bit of information, but every bit makes cracking
        the keys easier.

    '''
    
    blocksize = common.byte_size(pub_key.n)
    encrypted = transform.bytes2int(signature)
    decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
    clearsig = transform.int2bytes(decrypted, blocksize)

    # If we can't find the signature  marker, verification failed.
    if clearsig[0:2] != b('\x00\x01'):
        raise VerificationError('Verification failed')
    
    # Find the 00 separator between the padding and the payload
    try:
        sep_idx = clearsig.index(b('\x00'), 2)
    except ValueError:
        raise VerificationError('Verification failed')
    
    # Get the hash and the hash method
    (method_name, signature_hash) = _find_method_hash(clearsig[sep_idx+1:])
    message_hash = _hash(message, method_name)

    # Compare the real hash to the hash in the signature
    if message_hash != signature_hash:
        raise VerificationError('Verification failed')

    return True
Example #37
0
 def test_sign_different_key(self):
     '''Signing with another key should let the verification fail.'''
     
     (otherpub, _) = rsa.newkeys(512)
     
     message = b('je moeder')
     signature = pkcs1.sign(message, self.priv, 'SHA-256')
     self.assertRaises(pkcs1.VerificationError, pkcs1.verify,
                       message, signature, otherpub)
Example #38
0
    def test_write_varint(self):
        expected = b('\xac\x02')
        outfile = BytesIO()

        written = varblock.write_varint(outfile, 300)

        # Test the returned values
        self.assertEqual(expected, outfile.getvalue())
        self.assertEqual(2, written)
Example #39
0
    def test_sign_different_key(self):
        """Signing with another key should let the verification fail."""

        (otherpub, _) = rsa.newkeys(512)

        message = b('je moeder')
        signature = pkcs1.sign(message, self.priv, 'SHA-256')
        self.assertRaises(pkcs1.VerificationError, pkcs1.verify, message,
                          signature, otherpub)
Example #40
0
    def _save_pkcs1_pem(self):
        """Saves a PKCS#1 PEM-encoded private key file.

        :return: contents of a PEM-encoded file that contains the private key.
        :rtype: bytes
        """

        der = self._save_pkcs1_der()
        return rsa.pem.save_pem(der, b('RSA PRIVATE KEY'))
    def test_write_varint(self):
        expected = b('\xac\x02')
        outfile = BytesIO()

        written = varblock.write_varint(outfile, 300)

        # Test the returned values
        self.assertEqual(expected, outfile.getvalue())
        self.assertEqual(2, written)
Example #42
0
    def test_sign_verify(self):
        '''Test happy flow of sign and verify'''
        
        message = b('je moeder')
        print("\tMessage:   %r" % message)

        signature = pkcs1.sign(message, self.priv, 'SHA-256')
        print("\tSignature: %r" % signature)

        self.assertTrue(pkcs1.verify(message, signature, self.pub))
Example #43
0
    def test_sign_verify(self):
        """Test happy flow of sign and verify"""

        message = b('je moeder')
        print("\tMessage:   %r" % message)

        signature = pkcs1.sign(message, self.priv, 'SHA-256')
        print("\tSignature: %r" % signature)

        self.assertTrue(pkcs1.verify(message, signature, self.pub))
Example #44
0
    def test_sign_verify(self):
        '''Test happy flow of sign and verify'''
        
        message = b('je moeder')
        print("\tMessage:   %r" % message)

        signature = pkcs1.sign(message, self.priv, 'SHA-256')
        print("\tSignature: %r" % signature)

        pkcs1.verify(message, signature, self.pub)
Example #45
0
 def _load_pkcs1_pem(cls, keyfile):
     """Loads a PKCS#1 PEM-encoded private key file.
     
     The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
     after the "-----END RSA PRIVATE KEY-----" lines is ignored.
     
     @param keyfile: contents of a PEM-encoded file that contains the private
         key.
     @return: a PrivateKey object
     """
     der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY'))
     return cls._load_pkcs1_der(der)
Example #46
0
def _pad_for_encryption(message, target_length):
    r"""Pads the message for encryption, returning the padded message.
    
    :return: 00 02 RANDOM_DATA 00 MESSAGE
    
    >>> block = _pad_for_encryption('hello', 16)
    >>> len(block)
    16
    >>> block[0:2]
    '\x00\x02'
    >>> block[-6:]
    '\x00hello'
    
    """
    max_msglength = target_length - 11
    msglength = len(message)
    if msglength > max_msglength:
        raise OverflowError(
            '%i bytes needed for message, but there is only space for %i' %
            (msglength, max_msglength))
    padding = b('')
    padding_length = target_length - msglength - 3
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)
        new_padding = os.urandom(needed_bytes + 5)
        new_padding = new_padding.replace(b('\x00'), b(''))
        padding = padding + new_padding[:needed_bytes]

    return b('').join([b('\x00\x02'), padding, b('\x00'), message])
Example #47
0
    def _load_pkcs1_pem(cls, keyfile):
        '''Loads a PKCS#1 PEM-encoded private key file.

        The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
        after the "-----END RSA PRIVATE KEY-----" lines is ignored.

        @param keyfile: contents of a PEM-encoded file that contains the private
            key.
        @return: a PrivateKey object
        '''

        der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY'))
        return cls._load_pkcs1_der(der)
Example #48
0
    def test_zero(self):
        self.assertEqual(int2bytes(0, 4), b('\x00') * 4)
        self.assertEqual(int2bytes(0, 7), b('\x00') * 7)
        self.assertEqual(int2bytes(0), b('\x00'))

        self.assertEqual(_int2bytes(0, 4), b('\x00') * 4)
        self.assertEqual(_int2bytes(0, 7), b('\x00') * 7)
        self.assertEqual(_int2bytes(0), b('\x00'))
Example #49
0
    def test_zero(self):
        self.assertEqual(int2bytes(0, 4), b('\x00') * 4)
        self.assertEqual(int2bytes(0, 7), b('\x00') * 7)
        self.assertEqual(int2bytes(0), b('\x00'))

        self.assertEqual(_int2bytes(0, 4), b('\x00') * 4)
        self.assertEqual(_int2bytes(0, 7), b('\x00') * 7)
        self.assertEqual(_int2bytes(0), b('\x00'))
Example #50
0
    def test_encrypt_decrypt(self):
        with open('cleartext.txt', 'wb') as outfile:
            outfile.write(b'Hello cleartext RSA users!')

        with cli_args('-i', 'cleartext.txt', '--out=encrypted.txt', self.pub_fname):
            with captured_output():
                rsa.cli.encrypt()

        with cli_args('-i', 'encrypted.txt', self.priv_fname):
            with captured_output() as (out, err):
                rsa.cli.decrypt()

        # We should have the original cleartext on stdout now.
        output = get_bytes_out(out)
        self.assertEqual(b('Hello cleartext RSA users!'), output)
Example #51
0
    def test_encrypt_decrypt(self):
        with open('cleartext.txt', 'wb') as outfile:
            outfile.write(b'Hello cleartext RSA users!')

        with cli_args('-i', 'cleartext.txt', '--out=encrypted.txt',
                      self.pub_fname):
            with captured_output():
                rsa.cli.encrypt()

        with cli_args('-i', 'encrypted.txt', self.priv_fname):
            with captured_output() as (out, err):
                rsa.cli.decrypt()

        # We should have the original cleartext on stdout now.
        output = get_bytes_out(out)
        self.assertEqual(b('Hello cleartext RSA users!'), output)
Example #52
0
def _pad_for_encryption(message, target_length):
    max_msglength = target_length - 11
    msglength = len(message)
    if msglength > max_msglength:
        raise OverflowError(
            '%i bytes needed for message, but there is only space for %i' %
            (msglength, max_msglength))
    padding = b('')
    padding_length = target_length - msglength - 3
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)
        new_padding = os.urandom(needed_bytes + 5)
        new_padding = new_padding.replace(b('\x00'), b(''))
        padding = padding + new_padding[:needed_bytes]

    return b('').join([b('\x00\x02'), padding, b('\x00'), message])
Example #53
0
def _pad_for_encryption(message, target_length):
    max_msglength = target_length - 11
    msglength = len(message)
    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only space for %i' % (msglength, max_msglength))
    padding = b('')
    padding_length = target_length - msglength - 3
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)
        new_padding = os.urandom(needed_bytes + 5)
        new_padding = new_padding.replace(b('\x00'), b(''))
        padding = padding + new_padding[:needed_bytes]

    return b('').join([b('\x00\x02'),
     padding,
     b('\x00'),
     message])
Example #54
0
def _pad_for_encryption(message, target_length):
    r"""Pads the message for encryption, returning the padded message.

    :return: 00 02 RANDOM_DATA 00 MESSAGE

    >>> block = _pad_for_encryption(b'hello', 16)
    >>> len(block)
    16
    >>> block[0:2]
    b'\x00\x02'
    >>> block[-6:]
    b'\x00hello'

    """

    max_msglength = target_length - 11
    msglength = len(message)

    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only'
                            ' space for %i' % (msglength, max_msglength))

    # Get random padding
    padding = b('')
    padding_length = target_length - msglength - 3

    # We remove 0-bytes, so we'll end up with less padding than we've asked for,
    # so keep adding data until we're at the correct length.
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)

        # Always read at least 8 bytes more than we need, and trim off the rest
        # after removing the 0-bytes. This increases the chance of getting
        # enough bytes, especially when needed_bytes is small
        new_padding = os.urandom(needed_bytes + 5)
        new_padding = new_padding.replace(b('\x00'), b(''))
        padding = padding + new_padding[:needed_bytes]

    assert len(padding) == padding_length

    return b('').join([b('\x00\x02'),
                       padding,
                       b('\x00'),
                       message])
Example #55
0
def _pad_for_encryption(message, target_length):
    r'''Pads the message for encryption, returning the padded message.
    
    :return: 00 02 RANDOM_DATA 00 MESSAGE
    
    >>> block = _pad_for_encryption('hello', 16)
    >>> len(block)
    16
    >>> block[0:2]
    '\x00\x02'
    >>> block[-6:]
    '\x00hello'

    '''

    max_msglength = target_length - 11
    msglength = len(message)
    
    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only'
            ' space for %i' % (msglength, max_msglength))
    
    # Get random padding
    padding = b('')
    padding_length = target_length - msglength - 3
    
    # We remove 0-bytes, so we'll end up with less padding than we've asked for,
    # so keep adding data until we're at the correct length.
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)
        
        # Always read at least 8 bytes more than we need, and trim off the rest
        # after removing the 0-bytes. This increases the chance of getting
        # enough bytes, especially when needed_bytes is small
        new_padding = os.urandom(needed_bytes + 5)
        new_padding = new_padding.replace(b('\x00'), b(''))
        padding = padding + new_padding[:needed_bytes]
    
    assert len(padding) == padding_length
    
    return b('').join([b('\x00\x02'),
                    padding,
                    b('\x00'),
                    message])
Example #56
0
def _pad_zero(message, target_length):
    r'''Pads the message for encryption, returning the padded message.
    
    :return: 00 02 ZERO_BYTES 00 MESSAGE

    '''

    max_msglength = target_length - 11
    msglength = len(message)
    
    if msglength > max_msglength:
        raise OverflowError('%i bytes needed for message, but there is only'
            ' space for %i' % (msglength, max_msglength))
    
    # Get random padding
    padding = b('')
    padding_length = target_length - msglength - 3
    
    # We remove 0-bytes, so we'll end up with less padding than we've asked for,
    # so keep adding data until we're at the correct length.
    while len(padding) < padding_length:
        needed_bytes = padding_length - len(padding)
        
        # Always read at least 8 bytes more than we need, and trim off the rest
        # after removing the 0-bytes. This increases the chance of getting
        # enough bytes, especially when needed_bytes is small
        new_padding = b('\xff')
        for i in range(1,needed_bytes):
            new_padding = new_padding + b('\xff')
        padding = padding + new_padding[:needed_bytes]
        
    assert len(padding) == padding_length
    
    return b('').join([b('\x00\x02'),
                    padding,
                    b('\x00'),
                    message])   
Example #57
0
 def test_alter_message(self):
     '''Altering the message should let the verification fail.'''
     
     signature = pkcs1.sign(b('je moeder'), self.priv, 'SHA-256')
     self.assertRaises(pkcs1.VerificationError, pkcs1.verify,
                       b('mijn moeder'), signature, self.pub)
Example #58
0
def decrypt(crypto, priv_key):
    r'''Decrypts the given message using PKCS#1 v1.5
    
    The decryption is considered 'failed' when the resulting cleartext doesn't
    start with the bytes 00 02, or when the 00 byte between the padding and
    the message cannot be found.
    
    :param crypto: the crypto text as returned by :py:func:`rsa.encrypt`
    :param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with.
    :raise DecryptionError: when the decryption fails. No details are given as
        to why the code thinks the decryption fails, as this would leak
        information about the private key.


    >>> import rsa
    >>> (pub_key, priv_key) = rsa.newkeys(256)

    It works with strings:

    >>> crypto = encrypt('hello', pub_key)
    >>> decrypt(crypto, priv_key)
    'hello'
    
    And with binary data:

    >>> crypto = encrypt('\x00\x00\x00\x00\x01', pub_key)
    >>> decrypt(crypto, priv_key)
    '\x00\x00\x00\x00\x01'

    Altering the encrypted information will *likely* cause a
    :py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
    :py:func:`rsa.sign`.


    .. warning::

        Never display the stack trace of a
        :py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the
        code the exception occurred, and thus leaks information about the key.
        It's only a tiny bit of information, but every bit makes cracking the
        keys easier.

    >>> crypto = encrypt('hello', pub_key)
    >>> crypto = crypto[0:5] + 'X' + crypto[6:] # change a byte
    >>> decrypt(crypto, priv_key)
    Traceback (most recent call last):
    ...
    DecryptionError: Decryption failed

    '''

    blocksize = common.byte_size(priv_key.n)
    encrypted = transform.bytes2int(crypto)
    decrypted = core.decrypt_int(encrypted, priv_key.d, priv_key.n)
    cleartext = transform.int2bytes(decrypted, blocksize)

    # If we can't find the cleartext marker, decryption failed.
    if cleartext[0:2] != b('\x00\x02'):
        raise DecryptionError('Decryption failed')

    # Find the 00 separator between the padding and the message
    try:
        sep_idx = cleartext.index(b('\x00'), 2)
    except ValueError:
        raise DecryptionError('Decryption failed')

    return cleartext[sep_idx + 1:]
Example #59
0
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

'''Unittest for saving and loading keys.'''

import base64
import unittest
import os.path
import pickle

from rsa._compat import b

import rsa.key

B64PRIV_DER = b('MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt')
PRIVATE_DER = base64.standard_b64decode(B64PRIV_DER)

B64PUB_DER = b('MAwCBQDeKYlRAgMBAAE=')
PUBLIC_DER = base64.standard_b64decode(B64PUB_DER)

PRIVATE_PEM = b('''
-----BEGIN CONFUSING STUFF-----
Cruft before the key

-----BEGIN RSA PRIVATE KEY-----
Comment: something blah

%s
-----END RSA PRIVATE KEY-----