Beispiel #1
0
 def _test_signing(self, dsaObj):
     k = a2b_hex(self.k)
     m_hash = a2b_hex(self.m_hash)
     r = bytes_to_long(a2b_hex(self.r))
     s = bytes_to_long(a2b_hex(self.s))
     (r_out, s_out) = dsaObj.sign(m_hash, k)
     self.assertEqual((r, s), (r_out, s_out))
Beispiel #2
0
    def _exercise_primitive(self, rsaObj):
        # Since we're using a randomly-generated key, we can't check the test
        # vector, but we can make sure encryption and decryption are inverse
        # operations.
        ciphertext = a2b_hex(self.ciphertext)

        # Test decryption
        plaintext = rsaObj.decrypt((ciphertext,))

        # Test encryption (2 arguments)
        (new_ciphertext2,) = rsaObj.encrypt(plaintext, b(""))
        self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext2))

        # Test blinded decryption
        blinding_factor = Random.new().read(len(ciphertext)-1)
        blinded_ctext = rsaObj.blind(ciphertext, blinding_factor)
        blinded_ptext = rsaObj.decrypt((blinded_ctext,))
        unblinded_plaintext = rsaObj.unblind(blinded_ptext, blinding_factor)
        self.assertEqual(b2a_hex(plaintext), b2a_hex(unblinded_plaintext))

        # Test signing (2 arguments)
        signature2 = rsaObj.sign(ciphertext, b(""))
        self.assertEqual((bytes_to_long(plaintext),), signature2)

        # Test verification
        self.assertEqual(1, rsaObj.verify(ciphertext, (bytes_to_long(plaintext),)))
Beispiel #3
0
def generate_py(bits, randfunc, progress_func=None):
    """generate(bits:int, randfunc:callable, progress_func:callable)

    Generate a DSA key of length 'bits', using 'randfunc' to get
    random data and 'progress_func', if present, to display
    the progress of the key generation.
    """

    if bits < 160:
        raise ValueError('Key length < 160 bits')
    obj = DSAobj()
    # Generate string S and prime q
    if progress_func:
        progress_func('p,q\n')
    while (1):
        S, obj.q = generateQ(randfunc)
        n = divmod(bits - 1, 160)[0]
        C, N, V = 0, 2, {}
        b = (obj.q >> 5) & 15
        powb = pow(bignum(2), b)
        powL1 = pow(bignum(2), bits - 1)
        while C < 4096:
            for k in range(0, n + 1):
                V[k] = bytes_to_long(SHA.new(S + bstr(N) + bstr(k)).digest())
            W = V[n] % powb
            for k in range(n - 1, -1, -1):
                W = (W << 160) + V[k]
            X = W + powL1
            p = X - (X % (2 * obj.q) - 1)
            if powL1 <= p and isPrime(p):
                break
            C, N = C + 1, N + n + 1
        if C < 4096:
            break
        if progress_func:
            progress_func('4096 multiples failed\n')

    obj.p = p
    power = divmod(p - 1, obj.q)[0]
    if progress_func:
        progress_func('h,g\n')
    while (1):
        h = bytes_to_long(randfunc(bits)) % (p - 1)
        g = pow(h, power, p)
        if 1 < h < p - 1 and g > 1:
            break
    obj.g = g
    if progress_func:
        progress_func('x,y\n')
    while (1):
        x = bytes_to_long(randfunc(20))
        if 0 < x < obj.q:
            break
    obj.x, obj.y = x, pow(g, x, p)
    return obj
Beispiel #4
0
    def undigest(self, blocks):
        """undigest(blocks : [string]) : string

        Perform the reverse package transformation on a list of message
        blocks.  Note that the ciphermodule used for both transformations
        must be the same.  blocks is a list of strings of bit length
        equal to the ciphermodule's block_size.
        """

        # better have at least 2 blocks, for the padbytes package and the hash
        # block accumulator
        if len(blocks) < 2:
            raise ValueError("List must be at least length 2.")

        # blocks is a list of strings.  We need to deal with them as long
        # integers
        blocks = list(map(bytes_to_long, blocks))

        # Calculate the well-known key, to which the hash blocks are
        # encrypted, and create the hash cipher.
        K0 = self.__K0digit * self.__key_size
        hcipher = self.__newcipher(K0)
        block_size = self.__ciphermodule.block_size

        # Since we have all the blocks (or this method would have been called
        # prematurely), we can calculate all the hash blocks.
        hashes = []
        for i in range(1, len(blocks)):
            mticki = blocks[i-1] ^ i
            hi = hcipher.encrypt(long_to_bytes(mticki, block_size))
            hashes.append(bytes_to_long(hi))

        # now we can calculate K' (key).  remember the last block contains
        # m's' which we don't include here
        key = blocks[-1] ^ reduce(operator.xor, hashes)

        # and now we can create the cipher object
        mcipher = self.__newcipher(long_to_bytes(key, self.__key_size))

        # And we can now decode the original message blocks
        parts = []
        for i in range(1, len(blocks)):
            cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
            mi = blocks[i-1] ^ bytes_to_long(cipherblock)
            parts.append(mi)

        # The last message block contains the number of pad bytes appended to
        # the original text string, such that its length was an even multiple
        # of the cipher's block_size.  This number should be small enough that
        # the conversion from long integer to integer should never overflow
        padbytes = int(parts[-1])
        text = b('').join(map(long_to_bytes, parts[:-1]))
        return text[:-padbytes]
Beispiel #5
0
    def setUp(self):
        global RSA, Random, bytes_to_long
        from Crypro.PublicKey import RSA
        from Crypro import Random
        from Crypro.Util.number import bytes_to_long, inverse
        self.n = bytes_to_long(a2b_hex(self.modulus))
        self.p = bytes_to_long(a2b_hex(self.prime_factor))

        # Compute q, d, and u from n, e, and p
        self.q = divmod(self.n, self.p)[0]
        self.d = inverse(self.e, (self.p-1)*(self.q-1))
        self.u = inverse(self.p, self.q)    # u = e**-1 (mod q)

        self.rsa = RSA
Beispiel #6
0
    def _exercise_public_primitive(self, rsaObj):
        plaintext = a2b_hex(self.plaintext)

        # Test encryption (2 arguments)
        (new_ciphertext2,) = rsaObj.encrypt(plaintext, b(""))

        # Exercise verification
        rsaObj.verify(new_ciphertext2, (bytes_to_long(plaintext),))
Beispiel #7
0
 def test_construct_4tuple(self):
     """DSA (default implementation) constructed key (4-tuple)"""
     (y, g, p, q) = [
         bytes_to_long(a2b_hex(param))
         for param in (self.y, self.g, self.p, self.q)
     ]
     dsaObj = self.dsa.construct((y, g, p, q))
     self._test_verification(dsaObj)
Beispiel #8
0
    def _check_verification(self, rsaObj):
        signature = bytes_to_long(a2b_hex(self.plaintext))
        message = a2b_hex(self.ciphertext)

        # Test verification
        t = (signature,)     # rsaObj.verify expects a tuple
        self.assertEqual(1, rsaObj.verify(message, t))

        # Test verification with overlong tuple (this is a
        # backward-compatibility hack to support some harmless misuse of the
        # API)
        t2 = (signature, '')
        self.assertEqual(1, rsaObj.verify(message, t2)) # extra garbage at end of tuple
Beispiel #9
0
    def _decodeLen(self, idx, der):
        """Given a (part of a) DER element, and an index to the first byte of
                a DER length tag (L), return a tuple with the payload size,
                and the index of the first byte of the such payload (V).

                Raises a ValueError exception if the DER length is invalid.
                Raises an IndexError exception if the DER element is too short.
                """
        length = bord(der[idx])
        if length <= 127:
            return (length, idx + 1)
        payloadLength = bytes_to_long(der[idx + 1:idx + 1 + (length & 0x7F)])
        if payloadLength <= 127:
            raise ValueError("Not a DER length tag.")
        return (payloadLength, idx + 1 + (length & 0x7F))
Beispiel #10
0
def generateQ(randfunc):
    S = randfunc(20)
    hash1 = SHA.new(S).digest()
    hash2 = SHA.new(long_to_bytes(bytes_to_long(S) + 1)).digest()
    q = bignum(0)
    for i in range(0, 20):
        c = bord(hash1[i]) ^ bord(hash2[i])
        if i == 0:
            c = c | 128
        if i == 19:
            c = c | 1
        q = q * 256 + c
    while (not isPrime(q)):
        q = q + 2
    if pow(2, 159) < q < pow(2, 160):
        return S, q
    raise RuntimeError('Bad q value generated')
Beispiel #11
0
    def decode(self, derEle, noLeftOvers=0):
        """Decode a complete INTEGER DER element, and re-initializes this
                object with it.

                @param derEle       A complete INTEGER DER element. It must start with a DER
                                    INTEGER tag.
                @param noLeftOvers  Indicate whether it is acceptable to complete the
                                    parsing of the DER element and find that not all
                                    bytes in derEle have been used.
                @return             Index of the first unused byte in the given DER element.

                Raises a ValueError exception if the DER element is not a
                valid non-negative INTEGER.
                Raises an IndexError exception if the DER element is too short.
                """
        tlvLength = DerObject.decode(self, derEle, noLeftOvers)
        if self.typeTag != self.typeTags['INTEGER']:
            raise ValueError("Not a DER INTEGER.")
        if bord(self.payload[0]) > 127:
            raise ValueError("Negative INTEGER.")
        self.value = bytes_to_long(self.payload)
        return tlvLength
Beispiel #12
0
 def _test_verification(self, dsaObj):
     m_hash = a2b_hex(self.m_hash)
     r = bytes_to_long(a2b_hex(self.r))
     s = bytes_to_long(a2b_hex(self.s))
     self.assertEqual(1, dsaObj.verify(m_hash, (r, s)))
     self.assertEqual(0, dsaObj.verify(m_hash + b("\0"), (r, s)))
Beispiel #13
0
    def importKey(self, externKey, passphrase=None):
        """Import an RSA key (public or private half), encoded in standard form.

        :Parameter externKey:
            The RSA key to import, encoded as a string.

            An RSA public key can be in any of the following formats:

            - X.509 `subjectPublicKeyInfo` DER SEQUENCE (binary or PEM encoding)
            - `PKCS#1`_ `RSAPublicKey` DER SEQUENCE (binary or PEM encoding)
            - OpenSSH (textual public key only)

            An RSA private key can be in any of the following formats:

            - PKCS#1 `RSAPrivateKey` DER SEQUENCE (binary or PEM encoding)
            - `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE (binary or PEM encoding)
            - OpenSSH (textual public key only)

            For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
            
            In case of PEM encoding, the private key can be encrypted with DES or 3TDES according to a certain ``pass phrase``.
            Only OpenSSL-compatible pass phrases are supported.
        :Type externKey: string

        :Parameter passphrase:
            In case of an encrypted PEM key, this is the pass phrase from which the encryption key is derived.
        :Type passphrase: string
        
        :Return: An RSA key object (`_RSAobj`).

        :Raise ValueError/IndexError/TypeError:
            When the given key cannot be parsed (possibly because the pass phrase is wrong).

        .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
        .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
        .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
        .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
        """
        externKey = tobytes(externKey)
        if passphrase is not None:
            passphrase = tobytes(passphrase)

        if externKey.startswith(b('-----')):
            # This is probably a PEM encoded key
            lines = externKey.replace(b(" "), b('')).split()
            keyobj = None

            # The encrypted PEM format
            if lines[1].startswith(b('Proc-Type:4,ENCRYPTED')):
                DEK = lines[2].split(b(':'))
                if len(DEK) != 2 or DEK[0] != b('DEK-Info') or not passphrase:
                    raise ValueError("PEM encryption format not supported.")
                algo, salt = DEK[1].split(b(','))
                salt = binascii.a2b_hex(salt)
                import Crypro.Hash.MD5
                from Crypro.Cipher import DES, DES3
                from Crypro.Protocol.KDF import PBKDF1
                if algo == b("DES-CBC"):
                    # This is EVP_BytesToKey in OpenSSL
                    key = PBKDF1(passphrase, salt, 8, 1, Crypro.Hash.MD5)
                    keyobj = DES.new(key, Crypro.Cipher.DES.MODE_CBC, salt)
                elif algo == b("DES-EDE3-CBC"):
                    # Note that EVP_BytesToKey is note exactly the same as PBKDF1
                    key = PBKDF1(passphrase, salt, 16, 1, Crypro.Hash.MD5)
                    key += PBKDF1(key + passphrase, salt, 8, 1,
                                  Crypro.Hash.MD5)
                    keyobj = DES3.new(key, Crypro.Cipher.DES3.MODE_CBC, salt)
                else:
                    raise ValueError("Unsupport PEM encryption algorithm.")
                lines = lines[2:]

            der = binascii.a2b_base64(b('').join(lines[1:-1]))
            if keyobj:
                der = keyobj.decrypt(der)
                padding = bord(der[-1])
                der = der[:-padding]
            return self._importKeyDER(der)

        if externKey.startswith(b('ssh-rsa ')):
            # This is probably an OpenSSH key
            keystring = binascii.a2b_base64(externKey.split(b(' '))[1])
            keyparts = []
            while len(keystring) > 4:
                l = struct.unpack(">I", keystring[:4])[0]
                keyparts.append(keystring[4:4 + l])
                keystring = keystring[4 + l:]
            e = bytes_to_long(keyparts[1])
            n = bytes_to_long(keyparts[2])
            return self.construct([n, e])
        if bord(externKey[0]) == 0x30:
            # This is probably a DER encoded key
            return self._importKeyDER(externKey)

        raise ValueError("RSA key format is not supported")
Beispiel #14
0
    def digest(self, text):
        """digest(text:string) : [string]

        Perform the All-or-Nothing package transform on the given
        string.  Output is a list of message blocks describing the
        transformed text, where each block is a string of bit length equal
        to the ciphermodule's block_size.
        """

        # generate a random session key and K0, the key used to encrypt the
        # hash blocks.  Rivest calls this a fixed, publically-known encryption
        # key, but says nothing about the security implications of this key or
        # how to choose it.
        key = self._inventkey(self.__key_size)
        K0 = self.__K0digit * self.__key_size

        # we need two cipher objects here, one that is used to encrypt the
        # message blocks and one that is used to encrypt the hashes.  The
        # former uses the randomly generated key, while the latter uses the
        # well-known key.
        mcipher = self.__newcipher(key)
        hcipher = self.__newcipher(K0)

        # Pad the text so that its length is a multiple of the cipher's
        # block_size.  Pad with trailing spaces, which will be eliminated in
        # the undigest() step.
        block_size = self.__ciphermodule.block_size
        padbytes = block_size - (len(text) % block_size)
        text = text + b(' ') * padbytes

        # Run through the algorithm:
        # s: number of message blocks (size of text / block_size)
        # input sequence: m1, m2, ... ms
        # random key K' (`key' in the code)
        # Compute output sequence: m'1, m'2, ... m's' for s' = s + 1
        # Let m'i = mi ^ E(K', i) for i = 1, 2, 3, ..., s
        # Let m's' = K' ^ h1 ^ h2 ^ ... hs
        # where hi = E(K0, m'i ^ i) for i = 1, 2, ... s
        #
        # The one complication I add is that the last message block is hard
        # coded to the number of padbytes added, so that these can be stripped
        # during the undigest() step
        s = divmod(len(text), block_size)[0]
        blocks = []
        hashes = []
        for i in range(1, s+1):
            start = (i-1) * block_size
            end = start + block_size
            mi = text[start:end]
            assert len(mi) == block_size
            cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
            mticki = bytes_to_long(mi) ^ bytes_to_long(cipherblock)
            blocks.append(mticki)
            # calculate the hash block for this block
            hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
            hashes.append(bytes_to_long(hi))

        # Add the padbytes length as a message block
        i = i + 1
        cipherblock = mcipher.encrypt(long_to_bytes(i, block_size))
        mticki = padbytes ^ bytes_to_long(cipherblock)
        blocks.append(mticki)

        # calculate this block's hash
        hi = hcipher.encrypt(long_to_bytes(mticki ^ i, block_size))
        hashes.append(bytes_to_long(hi))

        # Now calculate the last message block of the sequence 1..s'.  This
        # will contain the random session key XOR'd with all the hash blocks,
        # so that for undigest(), once all the hash blocks are calculated, the
        # session key can be trivially extracted.  Calculating all the hash
        # blocks requires that all the message blocks be received, thus the
        # All-or-Nothing algorithm succeeds.
        mtick_stick = bytes_to_long(key) ^ reduce(operator.xor, hashes)
        blocks.append(mtick_stick)

        # we convert the blocks to strings since in Python, byte sequences are
        # always represented as strings.  This is more consistent with the
        # model that encryption and hash algorithms always operate on strings.
        return [long_to_bytes(i,self.__ciphermodule.block_size) for i in blocks]
Beispiel #15
0
    def _check_signing(self, rsaObj):
        signature = bytes_to_long(a2b_hex(self.plaintext))
        message = a2b_hex(self.ciphertext)

        # Test signing (2 argument)
        self.assertEqual((signature,), rsaObj.sign(message, b("")))
Beispiel #16
0
 def getrandbits(self, k):
     """Return a python long integer with k random bits."""
     if self._randfunc is None:
         self._randfunc = Random.new().read
     mask = (1 << k) - 1
     return mask & bytes_to_long(self._randfunc(ceil_div(k, 8)))
Beispiel #17
0
            usage(0)
        elif opt in ('-c', '--cipher'):
            ciphermodule = arg
        elif opt in ('-l', '--aslong'):
            aslong = 1

    # ugly hack to force __import__ to give us the end-path module
    module = __import__('Crypro.Cipher.'+ciphermodule, None, None, ['new'])

    x = AllOrNothing(module)
    print('Original text:\n==========')
    print(__doc__)
    print('==========')
    msgblocks = x.digest(b(__doc__))
    print('message blocks:')
    for i, blk in zip(list(range(len(msgblocks))), msgblocks):
        # base64 adds a trailing newline
        print('    %3d' % i, end=' ')
        if aslong:
            print(bytes_to_long(blk))
        else:
            print(base64.encodestring(blk)[:-1])
    #
    # get a new undigest-only object so there's no leakage
    y = AllOrNothing(module)
    text = y.undigest(msgblocks)
    if text == b(__doc__):
        print('They match!')
    else:
        print('They differ!')