Example #1
0
    def changepassword(self):
        """
        Creates a new key. The key itself is actually stored in
        the database in crypted form. This key is encrypted using the
        password that the user provides. This makes it easy to change the
        password for the database.
        If oldKeyCrypted is none, then a new password is generated."""
        if self._callback == None:
            raise CryptoNoCallbackException("No call back class has been specified")
        if self._keycrypted == None:
            # Generate a new key, 32 bits in length, if that's
            # too long for the Cipher, _getCipherReal will sort it out
            random = RandomPool()
            key = random.get_bytes(32).encode("base64")
        else:
            password = self._callback.execute("Please enter your current password")
            cipher = self._getcipher_real(password, self._algo)
            plainkey = cipher.decrypt(self._keycrypted.decode("base64"))
            key = self._retrievedata(plainkey)
        newpassword1 = self._callback.execute("Please enter your new password")
        newpassword2 = self._callback.execute("Please enter your new password again")
        if newpassword1 != newpassword2:
            raise CryptoPasswordMismatchException("Passwords do not match")
        newcipher = self._getcipher_real(newpassword1, self._algo)
        self._keycrypted = newcipher.encrypt(self._preparedata(key, newcipher.block_size)).encode("base64")

        # we also want to create the cipher if there isn't one already
        # so this CryptoEngine can be used from now on
        if self._cipher == None:
            self._cipher = self._getcipher_real(key.decode("base64"), self._algo)
            CryptoEngine._timeoutcount = time.time()

        return self._keycrypted
Example #2
0
 def get_random_bytes( nbytes ):
     nbits = nbytes * 8
     random_pool = RandomPool( 1064 )
     while random_pool.entropy < nbits:
         random_pool.add_event()
     random_pool.stir()
     return str( number.getRandomNumber( nbits, random_pool.get_bytes ) )
Example #3
0
 def generate_key(self):
     pool = RandomPool(384)
     pool.stir()
     randfunc = pool.get_bytes
     key_size = 1024
     self.private_key = RSA.generate(key_size, randfunc)
     self.public_key = self.private_key.publickey()
Example #4
0
 def _generate_seed(self, size):
     rp = RandomPool()
     for i in range(7):
         m = SHA.new()
         tempseed = rp.get_bytes(size)
         m.update(tempseed)
         rp.add_event(m.hexdigest())
     return rp.get_bytes(size)
Example #5
0
def AFSplit(data, stripes, digesttype='sha1'):
    """AF-Split data using digesttype.  Returned data size will be len(data) * stripes"""

    blockSize = len(data)

    rand = RandomPool()

    bufblock = "\x00" * blockSize

    ret = ""
    for i in range(0, stripes - 1):

        # Get some random data
        rand.randomize()
        rand.stir()
        r = rand.get_bytes(blockSize)
        if rand.entropy < 0:
            print
            "Warning: RandomPool entropy dropped below 0"

        ret += r
        bufblock = _xor(r, bufblock)
        bufblock = _diffuse(bufblock, blockSize, digesttype)
        rand.add_event(bufblock)

    ret += _xor(bufblock, data)
    return ret
Example #6
0
 def generate_key(self):
     '''
     Generate public and private session_key
     '''
     pool = RandomPool(384)
     pool.stir()
     randfunc = pool.get_bytes
     key_size = 1024
     key = RSA.generate(key_size, randfunc)
     public_key = key.publickey()
     return key, public_key
Example #7
0
def create_ssh_key():
    """
    Crate SSH key locally
    """
    key_size = 1024
    pool = RandomPool(key_size)
    pool.stir()
    rsakey = RSA.generate(key_size, pool.get_bytes)

    with open('private/gmailarchive_rsa', 'w') as k:
        k.write(rsakey.exportKey('PEM'))
    with open('private/gmailarchive_rsa.pub', 'w') as k:
        k.write(rsakey.publickey().exportKey('OpenSSH'))
Example #8
0
def AFSplit(data, stripes, digesttype='sha1'):
	"""AF-Split data using digesttype.  Returned data size will be len(data) * stripes"""

	blockSize = len(data)

	rand = RandomPool()

	bufblock = "\x00" * blockSize

	ret = ""
	for i in range(0, stripes-1):

		# Get some random data
		rand.randomize()
		rand.stir()
		r = rand.get_bytes(blockSize)
		if rand.entropy < 0:
			print "Warning: RandomPool entropy dropped below 0"

		ret += r
		bufblock = _xor(r, bufblock)
		bufblock = _diffuse(bufblock, blockSize, digesttype)
		rand.add_event(bufblock)

	ret += _xor(bufblock, data)
	return ret
Example #9
0
class FallbackRandomPool (BaseOSRandomPool):
    def __init__(self):
        self._wr = RandomPool()
        self.randomize()

    def get_bytes(self, n):
        return self._wr.get_bytes(n)
Example #10
0
class FallbackRandomPool(BaseOSRandomPool):
    def __init__(self):
        self._wr = RandomPool()
        self.randomize()

    def get_bytes(self, n):
        return self._wr.get_bytes(n)
Example #11
0
def privkeytostr(key, passphrase=None):
    keyData = '-----BEGIN RSA PRIVATE KEY-----\n'
    p, q = key.p, key.q
    if p > q:
        (p, q) = (q, p)
    # p is less than q
    objData = [
        0, key.n, key.e, key.d, q, p, key.d % (q - 1), key.d % (p - 1),
        util.number.inverse(p, q)
    ]
    if passphrase:
        iv = RandomPool().get_bytes(8)
        hexiv = ''.join(['%02X' % ord(x) for x in iv])
        keyData += 'Proc-Type: 4,ENCRYPTED\n'
        keyData += 'DEK-Info: DES-EDE3-CBC,%s\n\n' % hexiv
        ba = hashlib.md5(passphrase + iv).digest()
        bb = hashlib.md5(ba + passphrase + iv).digest()
        encKey = (ba + bb)[:24]
    asn1Data = asn1pack([objData])
    if passphrase:
        padLen = 8 - (len(asn1Data) % 8)
        asn1Data += (chr(padLen) * padLen)
        asn1Data = DES3.new(encKey, DES3.MODE_CBC, iv).encrypt(asn1Data)
    b64Data = base64.encodestring(asn1Data).replace('\n', '')
    b64Data = '\n'.join(
        [b64Data[i:i + 64] for i in range(0, len(b64Data), 64)])
    keyData += b64Data + '\n'
    keyData += '-----END RSA PRIVATE KEY-----'
    return keyData
Example #12
0
    def generate_public_key_pair(self, p1, p2, data):
        """
        The GENERATE PUBLIC-KEY PAIR command either initiates the generation 
        and storing of a key pair, i.e., a public key and a private key, in the
        card, or accesses a key pair previously generated in the card.
        
        :param p1: should be 0x00 (generate new key)
        :param p2: '00' (no information provided) or reference of the key to be generated
        :param data: One or more CRTs associated to the key generation if P1-P2 different from '0000'
        """

        from Crypto.PublicKey import RSA, DSA
        from Crypto.Util.randpool import RandomPool
        rnd = RandomPool()

        cipher = self.ct.algorithm

        c_class = locals().get(cipher, None)
        if c_class is None:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        if p1 & 0x01 == 0x00:  #Generate key
            PublicKey = c_class.generate(self.dst.keylength, rnd.get_bytes)
            self.dst.key = PublicKey
        else:
            pass  #Read key

        #Encode keys
        if cipher == "RSA":
            #Public key
            n = str(PublicKey.__getstate__()['n'])
            e = str(PublicKey.__getstate__()['e'])
            pk = ((0x81, len(n), n), (0x82, len(e), e))
            result = bertlv_pack(pk)
            #Private key
            d = PublicKey.__getstate__()['d']
        elif cipher == "DSA":
            #DSAParams
            p = str(PublicKey.__getstate__()['p'])
            q = str(PublicKey.__getstate__()['q'])
            g = str(PublicKey.__getstate__()['g'])
            #Public key
            y = str(PublicKey.__getstate__()['y'])
            pk = ((0x81, len(p), p), (0x82, len(q), q), (0x83, len(g), g),
                  (0x84, len(y), y))
            #Private key
            x = str(PublicKey.__getstate__()['x'])
        #Add more algorithms here
        #elif cipher = "ECDSA":
        else:
            raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])

        result = bertlv_pack([[0x7F49, len(pk), pk]])
        #TODO: Internally store key pair

        if p1 & 0x02 == 0x02:
            #We do not support extended header lists yet
            raise SwError["ERR_NOTSUPPORTED"]
        else:
            return SW["NORMAL"], result
Example #13
0
    def secure_chan(self, server_nick):
        """Request a secure channel."""
        if (self.config["crypto"] == "a"):
            # TODO: This key generation should be done elsewhere and better
            from Crypto.PublicKey import RSA
            from Crypto.Util.randpool import RandomPool
            from Crypto.Util import number             
            self.pool = RandomPool(384)
            self.pool.stir()
            # Larger key needed to encrypt larger data, 768 too small
            print "Generating key..."
            import cPickle
            # Only send public key, not private key
            # TODO: this needs to be fixed, its not seamless
            self.config["passwd"] = \
                cPickle.dumps(RSA.generate(1024, self.pool.get_bytes).publickey())

        msg = "sumi sec " + \
            self.config["crypto"] + \
            base64.encodestring(self.config["passwd"]).replace("\n", "")

        # Bootstrap sendmsg 
        #self.sendmsg(server_nick, msg)
        self.senders[server_nick]["sendmsg"](server_nick, msg)
        # Now, communicate in crypto with server_nick
        self.senders[server_nick]["crypto"] = self.config["crypto"]
        self.senders[server_nick]["passwd"] = self.config["passwd"]
Example #14
0
def gerar_chave_publica():
	pool = RandomPool(384)
	pool.stir()
	# randfunc(n) deve retornar uma string de dados aleatórios de
	# comprimento n, no caso de RandomPool, o método get_bytes
	randfunc = pool.get_bytes
	# Tamanho da chave, em bits
	N = 1024
	# Geramos a chave (contendo a chave pública e privada):
	key = RSA.generate(N, randfunc)
	# Separando apenas a chave pública:
	pub_key = key.publickey()
	arquivo = open(ARQ_CHAVE_PUBLICA, 'w')
	arquivo.write(pub_key.exportKey())
	arquivo.close()
	return pub_key
Example #15
0
    def generate_public_key_pair(self, p1, p2, data):
        """
        In the Cryptoflex card this command only supports RSA keys.

        :param data:
            Contains the public exponent used for key generation
        :param p1:
            The key number. Can be used later to refer to the generated key
        :param p2:
            Used to specify the key length. The mapping is: 0x40 => 256 Bit,
            0x60 => 512 Bit, 0x80 => 1024
        """
        from Crypto.PublicKey import RSA
        from Crypto.Util.randpool import RandomPool

        keynumber = p1  # TODO: Check if key exists

        keylength_dict = {0x40: 256, 0x60: 512, 0x80: 1024}

        if p2 not in keylength_dict:
            raise SwError(SW["ERR_INCORRECTP1P2"])
        else:
            keylength = keylength_dict[p2]

        rnd = RandomPool()
        PublicKey = RSA.generate(keylength, rnd.get_bytes)
        self.dst.key = PublicKey

        e_in = struct.unpack("<i", data)
        if e_in[0] != 65537:
            logging.warning("Warning: Exponents different from 65537 are " +
                            "ignored! The Exponent given is %i" % e_in[0])

        # Encode Public key
        n = PublicKey.__getstate__()['n']
        n_str = inttostring(n)
        n_str = n_str[::-1]
        e = PublicKey.__getstate__()['e']
        e_str = inttostring(e, 4)
        e_str = e_str[::-1]
        pad = 187 * '\x30'  # We don't have CRT components, so we need to pad
        pk_n = TLVutils.bertlv_pack(
            ((0x81, len(n_str), n_str), (0x01, len(pad), pad),
             (0x82, len(e_str), e_str)))
        # Private key
        d = PublicKey.__getstate__()['d']

        # Write result to FID 10 12 EF-PUB-KEY
        df = self.mf.currentDF()
        ef_pub_key = df.select("fid", 0x1012)
        ef_pub_key.writebinary([0], [pk_n])
        data = ef_pub_key.getenc('data')

        # Write private key to FID 00 12 EF-PRI-KEY (not necessary?)
        # How to encode the private key?
        ef_priv_key = df.select("fid", 0x0012)
        ef_priv_key.writebinary([0], [inttostring(d)])
        data = ef_priv_key.getenc('data')
        return PublicKey
Example #16
0
    def runTest(self):
        """Crypto.Util.randpool.RandomPool"""
        # Import the winrandom module and try to use it
        from Crypto.Util.randpool import RandomPool
        sys.stderr.write("SelfTest: You can ignore the RandomPool_DeprecationWarning that follows.\n")
        rpool = RandomPool()
        x = rpool.get_bytes(16)
        y = rpool.get_bytes(16)
        self.assertNotEqual(x, y)
        self.assertNotEqual(rpool.entropy, 0)

        rpool.randomize()
        rpool.stir('foo')
        rpool.add_event('foo')
Example #17
0
 def encrypt(self, data):
     """encrypt data with AES-CBC and sign it with HMAC-SHA256"""
     aes_key, hmac_key = self.keys
     pad = AES_BLOCK_SIZE - len(data) % AES_BLOCK_SIZE
     data = data + pad * chr(pad)
     iv_bytes = RandomPool(512).get_bytes(AES_BLOCK_SIZE)
     cypher = AES.new(aes_key, AES.MODE_CBC, iv_bytes)
     data = iv_bytes + cypher.encrypt(data)
     sig = hmac.new(hmac_key, data, hashlib.sha256).digest()
     return data + sig
Example #18
0
def encrypt(plain_text, passwd):
    '''Encrypts C{plain_text} using a key derived from C{passwd}.

    A key is derived from C{passwd} using L{_derive_key} with a random 8 byte
    salt. This key is then used to encrypt the following string:

        <len(plain)> + plain + "keysafe" + <random bytes>

    Then the salt and the ciphertext is concatenated and the result is base64
    encoded before being returned.

    @type plain_text: string
    @param plain_text: password
    @type passwd: string
    @param passwd: key to use for encryption
    @rtype: string
    @return: base64 encoded encryption of C{plain_text} using C{passwd}
    '''
    # TODO: Change the string to be encrypted to
    #  <len(plain)> + <plain> + <sha256(plain)> + <random bytes>
    # This should be better than using "keysafe" in the string

    # create the salt, and derive the key
    rp = RandomPool()
    salt = rp.get_bytes(8)
    key = _derive_key(passwd, salt)

    # create the full plain text string, make sure it matches the block size
    # for AES
    pt = plain_text + _KNOWN_STR
    rnd_pad_len = struct.unpack('B', rp.get_bytes(1))[0]
    rnd_pad_len += AES.block_size - \
            (1 + len(pt) + rnd_pad_len) % AES.block_size
    rnd_pad = rp.get_bytes(rnd_pad_len)
    full_plain_text = struct.pack('B', len(plain_text)) + pt + rnd_pad

    # encrypt, it seems I need to do it twice to get a predictable result
    cipher_block = AES.new(key, AES.MODE_PGP)
    cipher_text = cipher_block.encrypt(full_plain_text)
    cipher_text = cipher_block.encrypt(full_plain_text)

    return b64encode(salt + cipher_text)
Example #19
0
def salaa():
    #Allerkirjoitetaan sisalto
    #RSA avaimen luonti
    RSAkey = RSA.generate(1024, RandomPool().get_bytes)
    #Allekirjoitettavan tiedoston avaus ja luku
    SignFile = open(sys.argv[2], 'rb')
    contents = SignFile.read()
    SignFile.close()
    #Hashin laskeminen datalle
    hash1 = SHA.new(contents).digest()
    #Datan allekirjoitus
    signature = RSAkey.sign(hash1, "")
    #Julkisen avaimen tallennus
    pubkey = RSAkey.publickey()
    PubkeyFILE = open("pubkey.pem", 'w')
    PubkeyFILE.write(pubkey.exportKey('PEM'))
    PubkeyFILE.close()
    #Allekirjoituksen tallennus
    SigFILE = open("signature.txt", 'wb')
    test = signature[0]
    SigFILE.write(str(test))
    SigFILE.close()

    password = raw_input("Anna salasana:")
    key = hashlib.sha256(password).digest()
    #Luetaan julkinen avain tiedostoon
    publickeyFILE = open("julkinenavain", 'wb')
    publickeyFILE.write(key)
    publickeyFILE.close()
    #Moden valinta
    mode = AES.MODE_CBC
    iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
    #Salaimen luonti
    cipher = AES.new(key, mode, iv)
    #Salattavan tiedoston koko
    filesize = os.path.getsize(sys.argv[2])
    #Lohkon koko
    chunksize = AES.block_size * 16
    with open(sys.argv[2], 'rb') as infile:
        with open("salattusopimus.txt", 'wb') as outfile:
            #Tiedoston koon kirjoitus tiedoston alkuun
            outfile.write(struct.pack('<Q', filesize))
            outfile.write(iv)
            while True:
                chunk = infile.read(chunksize)
                if len(chunk) == 0:
                    break
                elif len(chunk) % 16 != 0:
                    chunk += ' ' * (AES.block_size -
                                    len(chunk) % AES.block_size)
                outfile.write(cipher.encrypt(chunk))
    outfile.close()
    infile.close()
Example #20
0
 def get_random_bytes(nbytes):
     nbits = nbytes * 8
     random_pool = RandomPool(1064)
     while random_pool.entropy < nbits:
         random_pool.add_event()
     random_pool.stir()
     return str(number.getRandomNumber(nbits, random_pool.get_bytes))
Example #21
0
    def runTest(self):
        """Crypto.Util.randpool.RandomPool"""
        # Import the winrandom module and try to use it
        from Crypto.Util.randpool import RandomPool
        sys.stderr.write("SelfTest: You can ignore the RandomPool_DeprecationWarning that follows.\n")
        rpool = RandomPool()
        x = rpool.get_bytes(16)
        y = rpool.get_bytes(16)
        self.assertNotEqual(x, y)
        self.assertNotEqual(rpool.entropy, 0)

        rpool.randomize()
        rpool.stir('foo')
        rpool.add_event('foo')
Example #22
0
    def changepassword(self):
        """
        Creates a new key. The key itself is actually stored in
        the database in crypted form. This key is encrypted using the
        password that the user provides. This makes it easy to change the
        password for the database.
        If oldKeyCrypted is none, then a new password is generated."""
        if (self._callback == None):
            raise CryptoNoCallbackException(
                "No call back class has been specified")
        if (self._keycrypted == None):
            # Generate a new key, 32 bits in length, if that's
            # too long for the Cipher, _getCipherReal will sort it out
            random = RandomPool()
            key = str(random.get_bytes(32)).encode('base64')
        else:
            password = self._callback.getsecret(
                "Please enter your current password")
            cipher = self._getcipher_real(password, self._algo)
            plainkey = cipher.decrypt(str(self._keycrypted).decode('base64'))
            key = self._retrievedata(plainkey)
        newpassword1 = self._callback.getsecret(
            "Please enter your new password")
        newpassword2 = self._callback.getsecret(
            "Please enter your new password again")
        if (newpassword1 != newpassword2):
            raise CryptoPasswordMismatchException("Passwords do not match")
        newcipher = self._getcipher_real(newpassword1, self._algo)
        self._keycrypted = str(
            newcipher.encrypt(self._preparedata(
                key, newcipher.block_size))).encode('base64')

        # we also want to create the cipher if there isn't one already
        # so this CryptoEngine can be used from now on
        if (self._cipher == None):
            self._cipher = self._getcipher_real(
                str(key).decode('base64'), self._algo)
            CryptoEngine._timeoutcount = time.time()

        return self._keycrypted
def pycryptest():
    from Crypto.PublicKey import RSA
    from Crypto.Hash import SHA
    from Crypto.Util.randpool import RandomPool
    r = RandomPool()
    k = RSA.generate(1024, r.get_bytes)
    progress("pycryptest key:", `(k.n, k.e)`)
    data = "abcdefg"
    
    dh = SHA.new(data).digest()
    sig = k.sign(dh, None)
    progress("pycryptest signature:", `sig`)
    result = k.verify(dh, sig)
    progress("pycryptest result:", result)
Example #24
0
def generate(bits, filename):
    rp = RandomPool()
    key = RSA.generate(bits, rp.get_bytes)
    public_key = key.publickey()
    public_dump = pickle.dumps(public_key)
    private_dump = pickle.dumps(key)

    try:
        fo = open(filename + ".priv", "w")
        fo.write(private_dump)
        fo.close

        fo = open(filename + ".pub", "w")
        fo.write(public_dump)
        fo.close
    except IOError, msg:
        print msg
        sys.exit(2)
def _encrypt(data, mode='RGB'):
    '''
  Encrypt the pixels (as a concatinated string).
  '''
    # unit: how many bytes does the smallest component have
    # size: how many components does each pixel have
    if mode == '1' or mode == 'I' or mode == 'F':
        print "Mode {mode} is not supported at the moment!".format(mode=mode)
        return []
    else:
        unit = 1
        format = 'B'
    cleartext = ''
    if type(data[0]) == int:
        pixel_size = 1
        for pixel in data:
            cleartext += chr(pixel)
    else:
        pixel_size = len(
            data[0])  # get the vector size based on the last pixel
        for pixel in data:
            for val in pixel:
                cleartext += chr(val)
    num_pixels = len(data)
    # encrypt the data string, pay attention to the length
    key = RandomPool().get_bytes(KEY_LEN)
    blowfish = Blowfish.new(key, mode=2)
    padding = '\x00' * (BLK_LEN - (len(cleartext) - 1) % BLK_LEN - 1)
    cleartext += padding
    ciphered = blowfish.encrypt(cleartext)
    ciphered = ciphered[len(
        padding):]  # don't really care if data is messed...
    ret = []
    chunk_size = unit * pixel_size
    for i in range(num_pixels):
        pixel = struct.unpack(format * pixel_size,
                              ciphered[chunk_size * i:chunk_size * (1 + i)])
        ret.append(pixel)
    return ret
Example #26
0
def gen_random_key(size=32):
    """
    Generate a cryptographically-secure random key. This is done by using
    Python 2.4's os.urandom, or PyCrypto.
    """
    import os
    if hasattr(os, "urandom"):  # Python 2.4+
        return os.urandom(size)

    # Try using PyCrypto if available
    try:
        from Crypto.Util.randpool import RandomPool
        from Crypto.Hash import SHA256
        return RandomPool(hash=SHA256).get_bytes(size)

    except ImportError:
        print >> sys.stderr, "WARNING: The generated key will not be cryptographically-secure key. Consider using Python 2.4+ to generate the key, or install PyCrypto."

        # Stupid random generation
        import random
        L = []
        for i in range(size):
            L.append(chr(random.randint(0, 255)))
        return "".join(L)
 def setup (self):
     # Set up a random pool; we won't bother to actually fill it with
     # entropy from the keyboard
     self.pool = RandomPool(384)
     self.pool.stir()
Example #28
0
    def create(self, file, cipherName, cipherMode, hashSpec, masterSize,
               stripes):
        """Initializes the file class passed in with the LUKS header

            Parameters
           cipherName: aes, cast5, blowfish
           cipherMode: cbc-plain, cbc-essiv:<hash>
           hashSpec: sha1, sha256, md5, ripemd160
           masterSize: length of the master key in bytes (must match cipher)
           stripes: number of stripes when Af Splitting keys

        For compatibility with the Linux kernel dm-crypt, hashSpec must equal "sha1"

        cbc-plain uses the sector number as the IV.  This has a weakness: an attacker
        may be able to detect the existance of watermarked files.
        cbc-essiv:<hash> protects against the weakness in cbc-plain, but is
        slightly slower. The digest size of the hash function passed to cbc-essiv
        must match the key size of the cipher.
        aes-cbc-essiv:sha256 works, while aes-cbc-essiv:sha1 does not

        For more information about the details of the attacks and risk assesment, see
        http://clemens.endorphin.org/LinuxHDEncSettings
        """

        if self.file != None:
            raise LuksError("This LuksFile has already been initialized")

        self._check_cipher(cipherName, cipherMode)

        self.magic = self.LUKS_MAGIC
        self.version = 1
        self.mkDigestIterations = 10
        self.keyBytes = masterSize
        self.hashSpec = hashSpec

        rand = RandomPool(self.SALT_SIZE + 16 + masterSize)

        # Generate the salt
        self.mkDigestSalt = rand.get_bytes(self.SALT_SIZE)

        # Generate a random master key
        self.masterKey = rand.get_bytes(self.keyBytes)
        self.ivGen.set_key(self.masterKey)

        # generate the master key digest
        pbkdf = PBKDFv2.PBKDFv2()
        self.mkDigest = pbkdf.makeKey(self.masterKey, self.mkDigestSalt,
                                      self.mkDigestIterations,
                                      hashlib.new(self.hashSpec).digest_size,
                                      self.hashSpec)

        # init the key information
        currentSector = math.ceil(592.0 / self.SECTOR_SIZE)
        alignSectors = 4096 / self.SECTOR_SIZE
        blocksPerStripe = math.ceil(
            float(self.keyBytes * stripes) / self.SECTOR_SIZE)

        self.keys = [None] * 8
        for i in range(0, 8):
            if currentSector % alignSectors > 0:
                currentSector += alignSectors - currentSector % alignSectors
            self.keys[i] = self._key_block()
            self.keys[i].create(currentSector, stripes, self.LUKS_KEY_DISABLED)
            currentSector += blocksPerStripe

        # Set the data offset
        if currentSector % alignSectors > 0:
            currentSector += alignSectors - currentSector % alignSectors
        self.payloadOffset = currentSector

        # Generate a UUID for this file
        self._uuidgen(rand)

        # Create a new file, and save the header into it
        self.file = file
        self._save_header()

        # Write FF into all the key slots
        FFData = "\xFF" * int(self.SECTOR_SIZE)
        for i in range(0, 8):
            self.file.seek(int(self.keys[i].keyMaterialOffset))
            for sector in range(0, int(blocksPerStripe)):
                self.file.write(FFData)

        # Flush the file to disk
        try:
            self.file.flush()
            os.fsync(self.file.fileno())
        except:
            # We might get an error because self.file.fileno() does not exist on StringIO
            pass
 def _get_random_pool(self):
     pool = RandomPool()
     pool.randomize()
     return pool
class key:
    """
    This may well be the only crypto class for Python that you'll ever need.
    Think of this class, and the ezPyCrypto module, as 'cryptography for
    the rest of us'.

    Designed to strike the optimal balance between ease of use, features
    and performance.

    Basic High-level methods:

     - L{encString} - encrypt a string
     - L{decString} - decrypt a string

     - L{encStringToAscii} - encrypt a string to a printable, mailable format
     - L{decStringFromAscii} - decrypt an ascii-format encrypted string

     - L{signString} - produce ascii-format signature of a string
     - L{verifyString} - verify a string against a signature

     - L{importKey} - import public key (and possibly private key too)
     - L{exportKey} - export public key only, as printable mailable string
     - L{exportKeyPrivate} - same, but export private key as well
     - L{makeNewKeys} - generate a new, random private/public key pair

    Middle-level (stream-oriented) methods:

     - L{encStart} - start a stream encryption session
     - L{encNext} - encrypt another piece of data
     - L{encEnd} - finalise stream encryption session

     - L{decStart} - start a stream decryption session
     - L{decNext} - decrypt the next piece of available data
     - L{decEnd} - finalise stream decryption session

    Low-level methods:

     - refer to the source code
    
    Principle of operation:

     - Data is encrypted with choice of symmetric block-mode session cipher
       (or default Blowfish if user doesn't care)
     - CFB block chaining is used for added security - each next block's
       key is affected by the previous block
     - The session key and initial value (IV) are encrypted against an RSA
       or ElGamal public key (user's choice, default RSA)
     - Each block in the stream is prepended with a 'length' byte, indicating
       how many bytes in the decrypted block are significant - needed when
       total data len mod block size is non-zero
     - Format of encrypted data is:
         - public key len - 2 bytes, little-endian - size of public key in bytes
        - public key - public key of recipient
        - block cipher len - unencrypted length byte - size of block cipher in bytes
        - block cipher - encrypted against public key, index into array
          of session algorithms
        - block key len - unencrypted length byte - size of block key in bytes
        - block key - encrypted against public key
        - block IV len - unencrypted length of block cipher IV - IV length in bytes
        - block cipher IV - encrypted against public key, prefixed 1-byte length
        - block1 len - 1 byte - number of significant chars in block1 *
        - block1 data - always 8 bytes, encrypted against session key
        - ...
        - blockn len
        - blockn data
        - If last data block is of the same size as the session cipher blocksize,
          a final byte 0x00 is sent.
    """
    
    #@<< class key declarations >>
    #@+node:1::<< class key declarations >>
    #@+body
    # Various lookup tables for encryption algorithms
    
    _algosPub = {'ElGamal':ElGamal, 'RSA':RSA}
    
    _algosPub1 = {ElGamal:'ElGamal', RSA:'RSA'}
    
    _algosSes = { "ARC2":ARC2, "Blowfish":Blowfish, "CAST":CAST,
                  "DES3":DES3, "IDEA":IDEA, "RC5":RC5}
    _algosSes1 = {'ARC2':0, 'Blowfish':1, 'CAST':2, 'DES3':3, 'IDEA':4, 'RC5':5}
    
    _algosSes2 = [ARC2, Blowfish, CAST, DES3, IDEA, RC5]
    
    _algosSes3 = {ARC2:'ARC2', Blowfish:'Blowfish', CAST:'CAST',
                  DES3:'DES3', IDEA:'IDEA', RC5:'RC5'}
    
    # Generate IV for passphrase encryption
    _passIV = "w8Z4(51fKH#p{!29Q05HWcb@K 6(1qdyv{9|4=+gvji$chw!9$38^2cyGK#;}'@DHx%3)q_skvh4#0*="
    
    # Buffer for yet-to-be-encrypted stream data
    _encBuf = ''
    
    #@-body
    #@-node:1::<< class key declarations >>


    #@+others
    #@+node:2::__init__
    #@+body
    def __init__(self, something = 512, algoPub=None, algoSess=None, **kwds):
        """Constructor. Creates a key object
    
        This constructor, when creating the key object, does one of
        two things:
         1. Creates a completely new keypair, OR
         2. Imports an existing keypair
    
        Arguments:
         1. If new keys are desired:
             - key size in bits (int), default 512 - advise at least 1536
             - algoPub - either 'RSA' or 'ElGamal' (default 'RSA')
             - algoSess - one of 'ARC2', 'Blowfish', 'CAST', 'DES3', 'IDEA', 'RC5',
               (default 'Blowfish')
         2. If importing an existing key or keypair:
             - keyobj (string) - result of a prior exportKey() call
        Keywords:
         - passphrase - default '':
            - If creating new keypair, this passphrase is used to encrypt privkey when
              exporting.
            - If importing a new keypair, the passphrase is used to authenticate and
              grant/deny access to private key
        """
        passphrase = kwds.get('passphrase', '')
    
        if type(something) is types.IntType:
            # which public key algorithm did they choose?
            if algoPub == None:
                algoPub = 'RSA'
            algoP = self._algosPub.get(algoPub, None)
            if algoP == None:
                # Whoops - don't know that one
                raise Exception("AlgoPub must be one of 'ElGamel', 'RSA' or 'DSA'")
            self.algoPub = algoP
            self.algoPname = algoPub
    
            # which session key algorithm?
            if algoSess == None:
                algoSess = 'Blowfish'
            algoS = self._algosSes.get(algoSess, None)
            if algoS == None:
                # Whoops - don't know that session algorithm
                raise Exception("AlgoSess must be one of AES/ARC2/Blowfish/CAST/DES/DES3/IDEA/RC5")
            self.algoSes = algoS
            self.algoSname = algoSess
    
            # organise random data pool
            self.randpool = RandomPool()
            self.randfunc = self.randpool.get_bytes
    
            # now create the keypair
            self.makeNewKeys(something, passphrase=passphrase)
    
        elif type(something) is types.StringType:
            if algoPub != None:
                raise Exception("Don't specify algoPub if importing a key")
            if self.importKey(something, passphrase=passphrase) == False:
                raise CryptoKeyError(
                    "Attempted to import invalid key, or passphrase is bad")
            self.randpool = RandomPool()
            self.randfunc = self.randpool.get_bytes
        else:
            raise Exception("Must pass keysize or importable keys")
    
    #@-body
    #@-node:2::__init__
    #@+node:3::makeNewKeys()
    #@+body
    def makeNewKeys(self, keysize=512, **kwds):
        """
        Creates a new keypair in cipher object, and a new session key
    
        Arguments:
         - keysize (default 512), advise at least 1536
        Returns:
         - None
        Keywords:
         - passphrase - used to secure exported private key - default '' (no passphrase)
    
        Keypair gets stored within the key object. Refer L{exportKey},
        L{exportKeyPrivate} and L{importKey}.
        
        Generally no need to call this yourself, since the constructor
        calls this in cases where you aren't instantiating with an
        importable key.
        """
    
        passphrase = kwds.get('passphrase', '')
        if passphrase == None:
            passphrase = ''
        self.passphrase = passphrase
    
        # set up a public key object
        self.randpool.stir()
        self.k = self.algoPub.generate(keysize, self.randfunc)
        self.randpool.stir()
        self._calcPubBlkSize()
    
        # Generate random session key
        self._genNewSessKey()
    
        # Create session cipher object
        self.randpool.stir()
    
        #trace()
    
        # Create a new block cipher object
        self._initBlkCipher()
    
    #@-body
    #@-node:3::makeNewKeys()
    #@+node:4::importKey()
    #@+body
    def importKey(self, keystring, **kwds):
        """
        Imports a public key or private/public key pair.
    
        (as previously exported from this object
        with the L{exportKey} or L{exportKeyPrivate} methods.)
    
        Arguments:
         - keystring - a string previously imported with
           L{exportKey} or L{exportKeyPrivate}
        Keywords:
         - passphrase - string (default '', meaning 'try to import without passphrase')
        Returns:
         - True if import successful, False if failed
    
        You don't have to call this if you instantiate your key object
        in 'import' mode - ie, by calling it with a previously exported key.
    
        Note - you shouldn't give a 'passphrase' when importing a public key.
        """
    
        passphrase = kwds.get('passphrase', '')
        if passphrase == None:
            passphrase = ''
    
        try:
            #k1 = keystring.split("<StartPycryptoKey>", 1)
            #k2 = k1[1].split("<EndPycryptoKey>")
            ##print "decoding:\n", k2[0]
            #k = base64.decodestring(k2[0])
    
            #trace()
    
            keypickle = self._unwrap("Key", keystring)
            keytuple = pickle.loads(keypickle)
            haspass, size, keyobj = keytuple
    
            if haspass:
                # decrypt against passphrase
                blksiz = 8 # lazy of me
    
                # create temporary symmetric cipher object for passphrase - hardwire to Blowfish
                ppCipher = Blowfish.new(passphrase,
                                        Blowfish.MODE_CFB,
                                        self._passIV[0:blksiz])
                enclen = len(keyobj)
                decpriv = ''
                i = 0
                while i < enclen:
                    decbit = ppCipher.decrypt(keyobj[i:i+blksiz])
                    decpriv += decbit
                    i += blksiz
                keyobj = decpriv[0:size]
        
            self.algoPname, self.k = pickle.loads(keyobj)
            self.algoPub = self._algosPub[self.algoPname]
    
            #raise Exception("Tried to import Invalid Key")
            self._calcPubBlkSize()
            self.passphrase = passphrase
            return True
        except:
            return False
    
    #@-body
    #@-node:4::importKey()
    #@+node:5::exportKey()
    #@+body
    def exportKey(self):
        """
        Exports the public key as a printable string.
    
        Exported keys can be imported elsewhere into MyCipher instances
        with the L{importKey} method.
        
        Note that this object contains only the public key. If you want to
        export the private key as well, call L{exportKeyPrivate} instaead.
    
        Note also that the exported string is Base64-encoded, and safe for sending
        in email.
    
        Arguments:
         - None
        Returns:
         - a base64-encoded string containing an importable key
        """
        rawpub = self._rawPubKey()
        expTuple = (False, None, rawpub)
        expPickle = pickle.dumps(expTuple, True)
        return self._wrap("Key", expPickle)
    
    #@-body
    #@-node:5::exportKey()
    #@+node:6::exportKeyPrivate()
    #@+body
    def exportKeyPrivate(self, **kwds):
        """
        Exports public/private key pair as a printable string.
    
        This string is a binary string consisting of a pickled key object,
        that can be imported elsewhere into MyCipher instances
        with the L{importKey} method.
        
        Note that this object contains the public AND PRIVATE keys.
        Don't EVER email any keys you export with this function (unless you
        know what you're doing, and you encrypt the exported keys against
        another key). When in doubt, use L{exportKey} instead.
    
        Keep your private keys safe at all times. You have been warned.
    
        Note also that the exported string is Base64-encoded, and safe for sending
        in email.
    
        Arguments:
         - None
        Keywords:
         - passphrase - default (None) to using existing passphrase. Set to '' to export
           without passphrase (if this is really what you want to do!)
        Returns:
         - a base64-encoded string containing an importable key
        """
    
        passphrase = kwds.get('passphrase', None)
        if passphrase == None:
            passphrase = self.passphrase
    
        # exported key is a pickle of the tuple:
        # (haspassphrase, keylen, keypickle)
        # if using passphrase, 'keypickle' is encrypted against blowfish, and 'keylen'
        # indicates the number of significant bytes.
    
        rawpriv = pickle.dumps((self.algoPname, self.k), True)
    
        # prepare the key tuple, depending on whether we're using passphrases
        if passphrase != '':
            blksiz = 8 # i'm getting lazy, assuming 8 for blowfish
    
            # encrypt this against passphrase
            ppCipher = Blowfish.new(passphrase,
                                    Blowfish.MODE_CFB,
                                    self._passIV[0:blksiz])
            keylen = len(rawpriv)
            extras = (blksiz - (keylen % blksiz)) % blksiz
            rawpriv += self.randfunc(extras) # padd with random bytes
            newlen = len(rawpriv)
            encpriv = ''
            #print "newlen = %d" % newlen
            #trace()
            i = 0
            while i < newlen:
                rawbit = rawpriv[i:i+blksiz]
                encbit = ppCipher.encrypt(rawpriv[i:i+blksiz])
                #print "i=%d rawbit len=%d, encbit len=%d" % (i, len(rawbit), len(encbit))
                encpriv += encbit
                i += blksiz
            #print "keylen=%d, newlen=%d, len(encpriv)=%d" % (keylen, newlen, len(encpriv))
            #trace()
            keytuple = (True, keylen, encpriv)
        else:
            keytuple = (False, None, rawpriv)
    
        # prepare final pickle, base64 encode, wrap
        keypickle = pickle.dumps(keytuple, True)
        return self._wrap("Key", keypickle)
    
    
    
    #@-body
    #@-node:6::exportKeyPrivate()
    #@+node:7::encString()
    #@+body
    def encString(self, raw):
        """
        Encrypt a string of data
    
        High-level func. encrypts an entire string of data, returning the encrypted
        string as binary.
    
        Arguments:
         - raw string to encrypt
        Returns:
         - encrypted string as binary
    
        Note - the encrypted string can be stored in files, but I'd suggest
        not emailing them - use L{encStringToAscii} instead. The sole advantage
        of this method is that it produces more compact data, and works a bit faster.
        """
    
        # All the work gets done by the stream level
        self.encStart()
    
        # carve up into segments, because Python gets really slow
        # at manipulating large strings
    
        size = len(raw)
        bits = []
        pos = 0
        chunklen = 1024
        while pos < size:
            bits.append(self.encNext(raw[pos:pos+chunklen]))
            pos += chunklen
        bits.append(self.encEnd())
    
        return "".join(bits)
    
    #@-body
    #@-node:7::encString()
    #@+node:8::encStringToAscii()
    #@+body
    def encStringToAscii(self, raw):
        """
        Encrypts a string of data to printable ASCII format
    
        Use this method instead of L{encString}, unless size and speed are
        major issues.
    
        This method returns encrypted data in bracketed  base64 format,
        safe for sending in email.
    
        Arguments:
         - raw - string to encrypt
        Returns:
         - enc - encrypted string, text-wrapped and Base-64 encoded, safe for
           mailing.
    
        There's an overhead with base64-encoding. It costs size, bandwidth and
        speed. Unless you need ascii-safety, use encString() instead.
        """
        enc = self.encString(raw)
        return self._wrap("Message", enc)
    
    #@-body
    #@-node:8::encStringToAscii()
    #@+node:9::decString()
    #@+body
    def decString(self, enc):
        """
        Decrypts a previously encrypted string.
    
        Arguments:
         - enc - string, previously encrypted in binary mode with encString
        Returns:
         - dec - raw decrypted string
        """
    
        chunklen = 1024
    
        size = len(enc)
        bits = []
        pos = 0
    
        self.decStart()
    
        # carve up into small chunks so we don't get any order n^2 on large strings
        while pos < size:
            bits.append(self.decNext(enc[pos:pos+chunklen]))
            pos += chunklen
    
        self.decEnd()
    
        dec = "".join(bits)
        return dec
    
    #@-body
    #@-node:9::decString()
    #@+node:10::decStringFromAscii()
    #@+body
    def decStringFromAscii(self, enc):
        """
        Decrypts a previously encrypted string in ASCII (base64)
        format, as created by encryptAscii()
    
        Arguments:
         - enc - ascii-encrypted string, as previously encrypted with
           encStringToAscii()
        Returns:
         - dec - decrypted string
    
        May generate an exception if the public key of the encrypted string
        doesn't match the public/private keypair in this key object.
    
        To work around this problem, either instantiate a key object with
        the saved keypair, or use the importKey() function.
    
        Exception will also occur if this object is not holding a private key
        (which can happen if you import a key which was previously exported
        via exportKey(). If you get this problem, use exportKeyPrivate() instead
        to export your keypair.
        """
        #trace()
        wrapped = self._unwrap("Message", enc)
        return self.decString(wrapped)
    
    #@-body
    #@-node:10::decStringFromAscii()
    #@+node:11::signString()
    #@+body
    def signString(self, raw):
        """
        Sign a string using private key
    
        Arguments:
         - raw - string to be signed
        Returns:
         - wrapped, base-64 encoded string of signature
    
        Note - private key must already be present in the key object.
        Call L{importKey} for the right private key first if needed.
        """
    
        # hash the key with MD5
        m = MD5.new()
        m.update(raw)
        d = m.digest()
        #print "sign: digest"
        #print repr(d)
    
        # sign the hash with our current public key cipher
        self.randpool.stir()
        k = getPrime(128, self.randfunc)
        self.randpool.stir()
        s = self.k.sign(d, k)
    
        # now wrap into a tuple with the public key cipher
        tup = (self.algoPname, s)
    
        # and pickle it
        p = pickle.dumps(tup, True)
    
        # lastly, wrap it into our base64
        w = self._wrap("Signature", p)
    
        return w
    
    #@-body
    #@-node:11::signString()
    #@+node:12::verifyString()
    #@+body
    def verifyString(self, raw, signature):
        """
        Verifies a string against a signature.
    
        Object must first have the correct public key loaded. (see
        L{importKey}). An exception will occur if this is not the case.
    
        Arguments:
         - raw - string to be verified
         - signature - as produced when key is signed with L{signString}
        Returns:
         - True if signature is authentic, or False if not
        """
    
        # unrwap the signature to a pickled tuple
        p = self._unwrap("Signature", signature)
    
        # unpickle
        algoname, rawsig = pickle.loads(p)
    
        # ensure we've got the right algorithm
        if algoname != self.algoPname:
            return False # wrong algorithm - automatic fail
    
        # hash the string
        m = MD5.new()
        m.update(raw)
        d = m.digest()
        #print "verify: digest"
        #print repr(d)
    
        # now verify the hash against sig
        if self.k.verify(d, rawsig):
            return True # signature valid, or very clever forgery
        else:
            return False # sorry
    
    #@-body
    #@-node:12::verifyString()
    #@+node:13::test()
    #@+body
    def test(self, raw):
        """
        Encrypts, then decrypts a string. What you get back should
        be the same as what you put in.
    
        This is totally useless - it just gives a way to test if this API
        is doing what it should.
        """
        enc = self.encString(raw)
        dec = self.decString(enc)
        return dec
    
    #@-body
    #@-node:13::test()
    #@+node:14::testAscii()
    #@+body
    def testAscii(self, raw):
        """
        Encrypts, then decrypts a string. What you get back should
        be the same as what you put in.
    
        This is totally useless - it just gives a way to test if this API
        is doing what it should.
        """
        enc = self.encStringToAscii(raw)
        dec = self.decStringFromAscii(enc)
        return dec
    
    #@-body
    #@-node:14::testAscii()
    #@+node:15::Stream Methods
    #@+body
    # ---------------------------------------------
    #
    # These methods provide stream-level encryption
    #
    # ---------------------------------------------
    
    
    #@-body
    #@+node:1::encStart()
    #@+body
    def encStart(self):
        """
        Starts a stream encryption session
        Sets up internal buffers for accepting ad-hoc data.
    
        No arguments needed, nothing returned.
        """
    
        # Create a header block of segments, each segment is
        # encrypted against recipient's public key, to enable
        # recipient to decrypt the rest of the stream.
    
        # format of header block is:
        #  - recipient public key
        #  - stream algorithm id
        #  - stream session key
        #  - stream cipher initial value
    
        # Take algorithm index and pad it to the max length
    
        # stick in pubkey
        pubkey = self._rawPubKey()
        pubkeyLen = len(pubkey)
    
        self._tstSessKey0 = ''
        self._tstSessKey1 = ''
        self._tstIV0 = ''
        self._tstIV1 = ''
        self._tstBlk0 = ''
        self._tstBlk1 = ''
    
        #print "pub key len=%d" % pubkeyLen
        
        len0 = pubkeyLen % 256
        len1 = pubkeyLen / 256
    
        # Create algorithms info blk. Structure is:
        #  1byte  - index into session ciphers table
        #  2bytes - session key len, LSB first
        #  1byte  - session IV len, LSB first
    
        while 1:
            self._encHdrs = chr(len0) + chr(len1) + pubkey
    
            # add algorithms index
            algInfo = chr(self._algosSes2.index(self.algoSes))
    
            # Create new session key
            self._genNewSessKey()
    
            # add session key length
            sessKeyLen = len(self.sessKey)
            sessKeyLenL = sessKeyLen % 256
            sessKeyLenH = sessKeyLen / 256
            algInfo += chr(sessKeyLenL) + chr(sessKeyLenH)
    
            # add session IV length
            sessIVLen = len(self.sessIV)
            algInfo += chr(sessIVLen)
            #alg += self.randfunc(self.pubBlkSize - 1) # add random chaff
            #encAlgNum = self._encRawPub(alg)
            encAlgEnc = self._encRawPub(self._padToPubBlkSize(algInfo))
            if encAlgEnc == None:
                continue
            #encAlgLen = len(encAlgNum)
            #self._encHdrs += chr(encAlgLen) + encAlgNum
            self._encHdrs += encAlgEnc
    
            # ensure we can encrypt session key in one hit
            if len(self.sessKey) > self.pubBlkSize:
                raise Exception(
                    "encStart: you need a bigger public key length")
    
            # encrypt and add session key
            sKeyEnc = self._encRawPub(self._padToPubBlkSize(self.sessKey))
            if sKeyEnc == None:
                continue
            # sKeyLen = len(sKeyEnc)
            # self._encHdrs += chr(sKeyLen) + sKeyEnc
            self._encHdrs += sKeyEnc
    
            # encrypt and add session cipher initial value
            sCipherInit = self._encRawPub(self._padToPubBlkSize(self.sessIV))
            if sCipherInit == None:
                continue
            # sCipherIVLen = len(sCipherInit)
            # self._encHdrs += chr(sCipherIVLen) + sCipherInit
            self._encHdrs += sCipherInit
    
            self._tstSessKey0 = self.sessKey
            self._tstIV0 = self.sessIV
    
            # Create a new block cipher object
            self._initBlkCipher()
    
            # ready to go!
            self._encBuf = ''
    
            # success
            break
    
    #@-body
    #@-node:1::encStart()
    #@+node:2::encNext()
    #@+body
    def encNext(self, raw=''):
        """
        Encrypt the next piece of data in a stream.
    
        Arguments:
         - raw - raw piece of data to encrypt
        Returns - one of:
         - '' - not enough data to encrypt yet - stored for later
         - encdata - string of encrypted data
        """
    
        if raw == '':
            return ''
    
        # grab any headers
        enc = self._encHdrs
        self._encHdrs = ''
    
        # add given string to our yet-to-be-encrypted buffer
        self._encBuf += raw
    
        # Loop on data, breaking it up and encrypting it in blocks. Don't
        # touch the last (n mod b) bytes in buffer, where n is total size and
        # b is blocksize
        size = len(self._encBuf)
        next = 0
        while next <= size - self.sesBlkSize: # skip trailing bytes for now
            # extract next block
            blk = self._encBuf[next:next+self.sesBlkSize]
    
            if self._tstBlk0 == '':
                self._tstBlk0 = blk
    
            # encrypt block against session key
            encpart = self.blkCipher.encrypt(blk)
    
            # add length byte and crypted block to internal buffer
            enc += chr(self.sesBlkSize) + encpart
    
            next += self.sesBlkSize
    
        # ditch what we've consumed from buffer
        self._encBuf = self._encBuf[next:]
        
        # return whatever we've encrypted so far
        return enc
    
    #@-body
    #@-node:2::encNext()
    #@+node:3::encEnd()
    #@+body
    def encEnd(self):
        """
        Called to terminate a stream session.
        Encrypts any remaining data in buffer.
    
        Arguments:
         - None
        Returns - one of:
         - last block of data, as a string
        """
    
        buf = ''
        if self._encBuf == '':
            # no trailing data - pass back empty packet
            return chr(0)
    
        # break up remaining data into packets, and encrypt
        while len(self._encBuf) > 0:
    
            # extract session blocksize worth of data from buf
            blk = self._encBuf[0:self.sesBlkSize]
            self._encBuf = self._encBuf[self.sesBlkSize:]
            blklen = len(blk)
    
            # pad if needed
            if blklen < self.sesBlkSize:
                blk += self.randfunc(self.sesBlkSize - blklen)
    
            # encrypt against session key, and add
            buf += chr(blklen)
            buf += self.blkCipher.encrypt(blk)
    
        # clean up and get out
        return buf
    
    #@-body
    #@-node:3::encEnd()
    #@+node:4::decStart()
    #@+body
    def decStart(self):
        """
        Start a stream decryption session.
    
        Call this method first, then feed in pieces of stream data into decNext until
        there's no more data to decrypt
    
        Arguments:
         - None
        Returns:
         - None
        """
    
        # Start with fresh buffer and initial state
        self._decBuf = ''
        self._decState = 'p'
        self._decEmpty = False
    
        self._tstSessKey1 = ''
        self._tstIV1 = ''
        self._tstBlk1 = ''
    
        # states - 'p'->awaiting public key
        #          'c'->awaiting cipher index
        #          'k'->awaiting session key
        #          'i'->awaiting cipher initial data
        #          'd'->awaiting data block
    
    #@-body
    #@-node:4::decStart()
    #@+node:5::decNext()
    #@+body
    def decNext(self, chunk):
        """
        Decrypt the next piece of incoming stream data.
    
        Arguments:
         - chunk - some more of the encrypted stream
        Returns (depending on state)
         - '' - no more decrypted data available just yet
         - data - the next available piece of decrypted data
         - None - session is complete - no more data available
        """
    
        if self._decEmpty:
            return None
    
        # add chunk to our buffer
        self._decBuf += chunk
    
        # bail out if nothing to do
        chunklen = len(self._decBuf)
        if chunklen < 2:
            return ''
    
        # start with empty decryption buffer
        decData = ''
    
        # loop around processing as much data as we can
        #print "decNext: started"
        while 1:
            if self._decState == 'p':
                size = ord(self._decBuf[0]) + 256 * ord(self._decBuf[1])
                if chunklen < size + 2:
                    # don't have full pubkey yet
                    return ''
                else:
                    pubkey = self._decBuf[2:size+2]
                    if not self._testPubKey(pubkey):
                        raise Exception("Can't decrypt - public key mismatch")
    
                    self._decBuf = self._decBuf[size+2:]
                    self._decState = 'c'
                    continue
    
            if self._decState == 'd':
    
                #trace()
    
                # awaiting next data chunk
                sizeReqd = self.sesBlkSize + 1
                size = len(self._decBuf)
                if size < sizeReqd:
                    return decData
                nbytes = ord(self._decBuf[0])
                if nbytes == 0:
                    self._decEmpty = True
                    return None
                blk = self._decBuf[1:sizeReqd]
                self._decBuf = self._decBuf[sizeReqd:]
                decBlk = self.blkCipher.decrypt(blk)
                if self._tstBlk1 == '':
                    self._tstBlk1 = decBlk
                decBlk = decBlk[0:nbytes]
                decData += decBlk
                if nbytes < self.sesBlkSize:
                    self._decEmpty = True
                    return decData
                continue
    
            if len(self._decBuf) < 2:
                return decData
    
            sizeReqd = ord(self._decBuf[0]) + 256 * ord(self._decBuf[1]) + 2
            size = len(self._decBuf)
    
            # bail if we have insufficient data
            if size < sizeReqd:
                return decData
    
            # extract length byte plus block
            #blksize = sizeReqd - 1
            #blk = self._decBuf[1:sizeReqd]
            #self._decBuf = self._decBuf[sizeReqd:]
            blk = self._decBuf[0:sizeReqd]
            self._decBuf = self._decBuf[sizeReqd:]
    
            # state-dependent processing
            if self._decState == 'c':
                #print "decrypting cipher info"
                # awaiting cipher info
                blk = self._decRawPub(blk)
    
                # session cipher index
                c = ord(blk[0])
                self.algoSes = self._algosSes2[c]
    
                # session key len
                self._tmpSessKeyLen = ord(blk[1]) + 256 * ord(blk[2])
    
                # session IV len
                self._tmpSessIVLen = ord(blk[3])
    
                # ignore the rest - it's just chaff
                self._decState = 'k'
                continue
    
            elif self._decState == 'k':
                # awaiting session key
                #print "decrypting session key"
                blk = self._decRawPub(blk)
                self.sessKey = blk[0:self._tmpSessKeyLen]
                self._tstSessKey1 = self.sessKey
                self._decState = 'i'
                continue
    
            elif self._decState == 'i':
                # awaiting cipher start value
                #print "decrypting IV"
                blk = self._decRawPub(blk)
                self.sessIV = blk[0:self._tmpSessIVLen]
                self._tstIV1 = self.sessIV
    
                # Create cipher object, now we have what we need
                self.blkCipher = self.algoSes.new(self.sessKey,
                                                  getattr(self.algoSes, "MODE_CFB"),
                                                  self.sessIV)
                self._calcSesBlkSize()
                self._decState = 'd'
                continue
    
            else:
                raise Exception(
                    "decNext: strange state '%s'" % self._decState[0])
    
    #@-body
    #@-node:5::decNext()
    #@+node:6::decEnd()
    #@+body
    def decEnd(self):
        """
        Ends a stream decryption session.
        """
        # nothing really to do here - decNext() has taken care of it
        # just reset internal state
        self._decBuf = ''
        self._decState = 'c'
    
    #@-body
    #@-node:6::decEnd()
    #@-node:15::Stream Methods
    #@+node:16::Low Level
    #@+node:1::_wrap()
    #@+body
    def _wrap(self, type, msg):
        """
        Encodes message as base64 and wraps with <StartPyCryptoname>/<EndPycryptoname>
        Args:
         - type - string to use in header/footer - eg 'Key', 'Message'
         - msg - binary string to wrap
        """
        return "<StartPycrypto%s>\n%s<EndPycrypto%s>\n" \
                 % (type, base64.encodestring(msg), type)
    
    #@-body
    #@-node:1::_wrap()
    #@+node:2::_unwrap()
    #@+body
    def _unwrap(self, type, msg):
        """
        Unwraps a previously _wrap()'ed message.
        """
        try:
            #trace()
            k1 = msg.split("<StartPycrypto%s>" % type, 1)
            k2 = k1[1].split("<EndPycrypto%s>" % type)
            k = k2[0]
            #print "raw = "
            #print k
            bin = base64.decodestring(k)
            return bin
        except:
            raise Exception("Tried to import Invalid %s" % type)
            self._calcBlkSize()
    
    #@-body
    #@-node:2::_unwrap()
    #@+node:3::_calcPubBlkSize()
    #@+body
    def _calcPubBlkSize(self):
        """
        Determine size of public key
        """
        self.pubBlkSize = (self.k.size() - 7) / 8
    
    #@-body
    #@-node:3::_calcPubBlkSize()
    #@+node:4::_encRawPub()
    #@+body
    def _encRawPub(self, raw):
        """
        Encrypt a small raw string using the public key
        algorithm. Input must not exceed the allowable
        block size.
    
        Arguments:
         - raw - small raw bit of string to encrypt
        Returns:
         - binary representation of encrypted chunk, or None if verify failed
        """
    
        if len(raw) > self.pubBlkSize:
            raise Exception(
                "_encraw: max len %d, passed %d bytes" % (self.pubBlkSize, len(raw)))
    
        self.randpool.stir()
        k = getPrime(128, self.randfunc)
        s = self.k.encrypt(raw, k)
        #d = self.k.decrypt(s)
        #if d != raw:
        #    #print "_encRawPub: decrypt verify fail"
        #    return None
    
        #trace()
    
        # format this tuple into <len><nitems><item1len><item1bytes><item2len><item2bytes>...
        enc = chr(len(s))
        for item in s:
            itemLen = len(item)
            itemLenL = itemLen % 256
            itemLenH = itemLen / 256
            #enc += chr(len(item))
            enc += chr(itemLenL) + chr(itemLenH)
            enc += item
        encLen = len(enc)
        encLenL = encLen % 256
        encLenH = encLen / 256
        #enc = chr(len(enc)) + enc
        enc = chr(encLenL) + chr(encLenH) + enc
    
        #d = self._decRawPub(enc)
        #if d != raw:
        #    print "panic:_encRawPub: decrypt verify fail!"
            
        return enc
    
    
    #@-body
    #@-node:4::_encRawPub()
    #@+node:5::_decRawPub()
    #@+body
    def _decRawPub(self, enc):
        """
        Decrypt a public-key encrypted block, and return the decrypted string
    
        Arguments:
         - enc - the encrypted string, in the format as created by _encRawPub()
        Returns:
         - decrypted block
        """
    
        #trace()
    
        blklen = ord(enc[0]) + 256 * ord(enc[1])
        nparts = ord(enc[2])
        enc = enc[3:]
    
        if blklen != len(enc)+1:
            raise Exception(
                "_decRawPub: bad block length %d, should be %d" % (len(enc), blklen))
        parts = []
        for i in range(nparts):
            partlen = ord(enc[0]) + 256 * ord(enc[1])
            part = enc[2:partlen+2]
            enc = enc[partlen+2:]
            parts.append(part)
        partsTuple = tuple(parts)
        dec = self.k.decrypt(partsTuple)
        return dec
    
    
    
    #@-body
    #@-node:5::_decRawPub()
    #@+node:6::_initBlkCipher()
    #@+body
    def _initBlkCipher(self):
        """
        Create a new block cipher object, set up with a new session key
        and IV
        """
    
        self.blkCipher = self.algoSes.new(self.sessKey,
                                          getattr(self.algoSes, "MODE_CFB"),
                                          self.sessIV)
        self._calcSesBlkSize()
    
    #@-body
    #@-node:6::_initBlkCipher()
    #@+node:7::_calcSesBlkSize()
    #@+body
    def _calcSesBlkSize(self):
        """
        Determine size of session blocks
        """
        self.sesBlkSize = (self.blkCipher.block_size)
    
    #@-body
    #@-node:7::_calcSesBlkSize()
    #@+node:8::_testPubKey()
    #@+body
    def _testPubKey(self, k):
        """
        Checks if binary-encoded key matches this object's pubkey
        """
    
        if k == self._rawPubKey():
            return True
        else:
            return False
    
    #@-body
    #@-node:8::_testPubKey()
    #@+node:9::_rawPubKey()
    #@+body
    def _rawPubKey(self):
        """
        Returns a binary-encoded string of public key
        """
        return pickle.dumps((self.algoPname, self.k.publickey()), True)
    
    #@-body
    #@-node:9::_rawPubKey()
    #@+node:10::_padToPubBlkSize()
    #@+body

    def _padToPubBlkSize(self, raw):
        """
        padToPubBlkSize - pad a string to max size encryptable by public key
    
        Defence against factoring attacks that can uplift a session key when
        that key is encrypted by itself against public key
    
        Arguments:
         - raw - string to pad with random bytes
        returns:
         - padded string. Note - it is the responsibility of the decryption
           code to know how much of the string to extract once decrypted.
        """
    
        rawlen = len(raw)
        extras = self.randfunc(self.pubBlkSize - rawlen)
        #print "padToPubBlkSize: len=%d, added %d bytes of chaff :)" \
        #      % (rawlen, len(extras))
        return raw + extras
    
    #@-body
    #@-node:10::_padToPubBlkSize()
    #@+node:11::_genNewSessKey()
    #@+body
    def _genNewSessKey(self):
        """
        Generate a new random session key
        """
        self.randpool.stir()
        self.sessKey = self.randfunc(32)
        self.randpool.stir()
        self.sessIV = self.randfunc(8)
 def __init__(self, something = 512, algoPub=None, algoSess=None, **kwds):
     """Constructor. Creates a key object
 
     This constructor, when creating the key object, does one of
     two things:
      1. Creates a completely new keypair, OR
      2. Imports an existing keypair
 
     Arguments:
      1. If new keys are desired:
          - key size in bits (int), default 512 - advise at least 1536
          - algoPub - either 'RSA' or 'ElGamal' (default 'RSA')
          - algoSess - one of 'ARC2', 'Blowfish', 'CAST', 'DES3', 'IDEA', 'RC5',
            (default 'Blowfish')
      2. If importing an existing key or keypair:
          - keyobj (string) - result of a prior exportKey() call
     Keywords:
      - passphrase - default '':
         - If creating new keypair, this passphrase is used to encrypt privkey when
           exporting.
         - If importing a new keypair, the passphrase is used to authenticate and
           grant/deny access to private key
     """
     passphrase = kwds.get('passphrase', '')
 
     if type(something) is types.IntType:
         # which public key algorithm did they choose?
         if algoPub == None:
             algoPub = 'RSA'
         algoP = self._algosPub.get(algoPub, None)
         if algoP == None:
             # Whoops - don't know that one
             raise Exception("AlgoPub must be one of 'ElGamel', 'RSA' or 'DSA'")
         self.algoPub = algoP
         self.algoPname = algoPub
 
         # which session key algorithm?
         if algoSess == None:
             algoSess = 'Blowfish'
         algoS = self._algosSes.get(algoSess, None)
         if algoS == None:
             # Whoops - don't know that session algorithm
             raise Exception("AlgoSess must be one of AES/ARC2/Blowfish/CAST/DES/DES3/IDEA/RC5")
         self.algoSes = algoS
         self.algoSname = algoSess
 
         # organise random data pool
         self.randpool = RandomPool()
         self.randfunc = self.randpool.get_bytes
 
         # now create the keypair
         self.makeNewKeys(something, passphrase=passphrase)
 
     elif type(something) is types.StringType:
         if algoPub != None:
             raise Exception("Don't specify algoPub if importing a key")
         if self.importKey(something, passphrase=passphrase) == False:
             raise CryptoKeyError(
                 "Attempted to import invalid key, or passphrase is bad")
         self.randpool = RandomPool()
         self.randfunc = self.randpool.get_bytes
     else:
         raise Exception("Must pass keysize or importable keys")
Example #32
0
class Random:
    def __init__(self):
        from Crypto.Util.randpool import RandomPool
        self.RandomPool = RandomPool()

    def getRandomString(self, N):
        """Returns a N-bit length random string."""
        r = self.getRandomNumber(N)


        return number.long_to_bytes(r)
    
    def getRandomNumber(self, N):
        """Returns an N-bit length random number."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)
            
        self.RandomPool.add_event('')
        self.RandomPool.stir()

        random = number.getRandomNumber(N, self.RandomPool.get_bytes)

        self.RandomPool.stir()

        return random

    def getPrime(self, N):
        """Returns a N-bit length prime."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)

        self.RandomPool.add_event('')
        self.RandomPool.stir()

        prime = number.getPrime(N, self.RandomPool.get_bytes)

        self.RandomPool.stir()
        
        return prime

    def addEvent(self, text):
        """Adds a bit of random text to the pool as additional entropy. Use caution.
        The curreny implementation of this function just XORs the text over the entropy, probably
        giving it bias if we just roll through our messages. I'm not sure.
        """
        self.RandomPool.add_event(text)
        self.RandomPool.stir()

    def verifyEntropy(self, N):
        """Verifies enough entropy is in the RandomPool. If we are close to no entropy, attempt to add some."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)

        self.RandomPool.add_event('')
        self.RandomPool.stir()

        if self.RandomPool.entropy < N: # if the stirring got rid of entropy, seed with more entropy
            self.verifyEntropy(2 * N)

    def get_bytes(self, num):
        """Get num bytes of randomness from the RandomPool."""
        return self.RandomPool.get_bytes(num)
Example #33
0
 def __init__(self):
     self._wr = RandomPool()
     self.randomize()
Example #34
0
class Random:
    def __init__(self):
        from Crypto.Util.randpool import RandomPool
        self.RandomPool = RandomPool()

    def getRandomString(self, N):
        """Returns a N-bit length random string."""
        r = self.getRandomNumber(N)

        return number.long_to_bytes(r)

    def getRandomNumber(self, N):
        """Returns an N-bit length random number."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)

        self.RandomPool.add_event('')
        self.RandomPool.stir()

        random = number.getRandomNumber(N, self.RandomPool.get_bytes)

        self.RandomPool.stir()

        return random

    def getPrime(self, N):
        """Returns a N-bit length prime."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)

        self.RandomPool.add_event('')
        self.RandomPool.stir()

        prime = number.getPrime(N, self.RandomPool.get_bytes)

        self.RandomPool.stir()

        return prime

    def addEvent(self, text):
        """Adds a bit of random text to the pool as additional entropy. Use caution.
        The curreny implementation of this function just XORs the text over the entropy, probably
        giving it bias if we just roll through our messages. I'm not sure.
        """
        self.RandomPool.add_event(text)
        self.RandomPool.stir()

    def verifyEntropy(self, N):
        """Verifies enough entropy is in the RandomPool. If we are close to no entropy, attempt to add some."""
        if self.RandomPool.entropy < 2 * N:
            self.RandomPool.randomize(4 * N)

        self.RandomPool.add_event('')
        self.RandomPool.stir()

        if self.RandomPool.entropy < N:  # if the stirring got rid of entropy, seed with more entropy
            self.verifyEntropy(2 * N)

    def get_bytes(self, num):
        """Get num bytes of randomness from the RandomPool."""
        return self.RandomPool.get_bytes(num)
Example #35
0
#!/usr/bin/env python

# Script to time fast and slow RSA operations
# Contributed by Joris Bontje.

import time, pprint
from Crypto.PublicKey import *
from Crypto.Util.randpool import RandomPool
from Crypto.Util import number

pool = RandomPool()
pool.stir()

KEYSIZE = 2048
COUNT = 5
fasttime = 0
slowtime = 0
for x in range(COUNT):
    begintime = time.time()
    rsa = RSA.generate(KEYSIZE, pool.get_bytes)
    endtime = time.time()
    print "Server: Generating %d bit RSA key: %f s" % (KEYSIZE,
                                                       endtime - begintime)
    rsa_slow = RSA.construct((rsa.n, rsa.e, rsa.d))

    code = number.getRandomNumber(256, pool.get_bytes)
    begintime = time.time()
    signature = rsa.sign(code, None)[0]
    endtime = time.time()
    fast = (endtime - begintime)
    fasttime = fasttime + fast
Example #36
0
        try:
            _urandom = file('/dev/urandom', 'rb')
        except IOError:
            raise ImportError('No adequate source of randomness found!')
        else:

            def getBytes(n):
                bytes = []
                while n:
                    chunk = _urandom.read(n)
                    n -= len(chunk)
                    bytes.append(chunk)
                    assert n >= 0
                return ''.join(bytes)
    else:
        _pool = RandomPool()

        def getBytes(n, pool=_pool):
            if pool.entropy < n:
                pool.randomize()
            return pool.get_bytes(n)


# A randrange function that works for longs
try:
    randrange = random.SystemRandom().randrange
except AttributeError:
    # In Python 2.2's random.Random, randrange does not support
    # numbers larger than sys.maxint for randrange. For simplicity,
    # use this implementation for any Python that does not have
    # random.SystemRandom
Example #37
0
    def set_key(self, keyIndex, password, iterations, checkMinStripes=0):
        """Sets the key block at keyIndex using password

        Sets the key block at keyIndex using password, hashed iterations
        times using PBKDFv2 (RFC2104).  This LuksFile must be unlocked by
        calling open_any_key() before calling this function.
        checkMinStripes is used to detect basic header manipulation, since
        the number of stripes for the key is set by create(), before
        we write a password to disk we make sure the key is not weak because
        of a small number of stripes.

        This function will raise an error if the key is already enabled.
        """

        # Some checks
        if self.masterKey == None:
            raise LuksError(
                "A key has not been unlocked.  Call open_any_key() first.")

        if keyIndex < 0 or keyIndex > 7:
            raise LuksError("keyIndex out of range")

        key = self.keys[keyIndex]
        if key.active != self.LUKS_KEY_DISABLED:
            raise LuksError("Key is active.  Delete the key and try again")

        if checkMinStripes == 0: checkMinStripes = self.KEY_STRIPES
        if key.stripes < checkMinStripes:
            raise LuksError(
                "Key section %i contains too few stripes.  Header manipulation?"
                % keyIndex)

        key.passwordIterations = iterations

        # Generate a random salt for this key
        rand = RandomPool(self.SALT_SIZE)
        key.passwordSalt = rand.get_bytes(self.SALT_SIZE)

        # Hash the key using PBKDFv2
        pbkdf = PBKDFv2.PBKDFv2()
        derived_key = pbkdf.makeKey(password, key.passwordSalt,
                                    key.passwordIterations, self.keyBytes,
                                    self.hashSpec)

        # Split the key into key.stripes
        AfKey = AfSplitter.AFSplit(self.masterKey, key.stripes, self.hashSpec)

        AfKeySize = len(AfKey)
        if AfKeySize != key.stripes * self.keyBytes:
            raise LuksError(
                "ERROR: AFSplit did not return the correct length of key")

        # Set the key for IV generation
        self.ivGen.set_key(derived_key)

        # Encrypt the splitted key using the hashed password
        AfSectors = int(math.ceil(float(AfKeySize) / self.SECTOR_SIZE))
        for sector in range(0, AfSectors):
            self._encrypt_sector(derived_key, key.keyMaterialOffset + sector, sector, \
                                 AfKey[int(sector * self.SECTOR_SIZE):int((sector + 1) * self.SECTOR_SIZE)])

        key.active = self.LUKS_KEY_ENABLED

        # Reset the key used for to IV generation in data mode
        self.ivGen.set_key(self.masterKey)

        self._save_header()
class PublicKeyTest (TestScenario):

    def setup (self):
        # Set up a random pool; we won't bother to actually fill it with
        # entropy from the keyboard
        self.pool = RandomPool(384)
        self.pool.stir()

    def shutdown (self):
        del self.pool

    def testkey (self, key, randfunc, verbose=0):
        plaintext="Hello"
        # Generate maximum-size plaintext
        maxplain = (key.size() // 8) * '\377'

        if key.can_encrypt():
            if verbose: print '  Encryption/decryption test'
            K=number.getPrime(10, randfunc)
            ciphertext=key.encrypt(plaintext, K)
            self.test_val('key.decrypt(ciphertext)', plaintext)
            ciphertext=key.encrypt(maxplain, K)
            self.test_val('key.decrypt(ciphertext)', maxplain)

        if key.can_sign():
            if verbose: print '  Signature test'
            K=number.getPrime(30, randfunc)
            signature=key.sign(plaintext, K)
            self.test_bool('key.verify(plaintext, signature)')
            self.test_bool('key.verify(plaintext[:-1], signature)',
                           want_true=0)

            # Change a single bit in the plaintext
            badtext=plaintext[:-3]+chr( 1 ^ ord(plaintext[-3]) )+plaintext[-3:]
            self.test_bool('key.verify(badtext, signature)', want_true=0)

            if verbose: print '  Removing private key data'
            pubonly=key.publickey()
            self.test_bool('pubonly.verify(plaintext, signature)')

        # Test blinding
        if key.can_blind():
            if verbose: print '  Blinding test'
            K=number.getPrime(30, randfunc)
            B="garbage"
            blindedtext=key.blind(plaintext, B)
            signature=key.sign(blindedtext, K)
            unblindedsignature=(key.unblind(signature[0], B),)
            self.test_bool('key.verify(plaintext, unblindedsignature)')
            self.test_val('key.sign(plaintext, K)', unblindedsignature)

            # Change a single bit in the blinding factor
            badB=B[:-3]+chr( 1 ^ ord(B[-3]) )+B[-3:]
            badunblindedsignature=(key.unblind(signature[0], badB),)
            self.test_false('key.verify(badtext, badunblindedsignature)')

            badblindedtext=key.blind(plaintext, badB)
            badsignature=key.sign(blindedtext, K)
            badunblindedsignature2=(key.unblind(signature[0], B),)
            self.test_false('key.verify(badtext, badunblindedsignature2)')


    def exercise (self, randfunc, pk_mod, verbose=0):
        N=256                           # Key size, measured in bits

        key=pk_mod.generate(N, randfunc)

        if verbose:
            print ' Key data:'
            for field in key.keydata:
                print "  ", field, ':', hex(getattr(key,field))

        if verbose: print " Testing newly generated key"
        self.testkey(key, randfunc, verbose)
        if verbose: print " Testing pickled/unpickled key"
        import pickle
        s = pickle.dumps(key) ; key2 = pickle.loads(s)
        self.testkey(key2, randfunc, verbose)

        if verbose: print " Testing cPickled key"
        s = cPickle.dumps(key) ; key2 = cPickle.loads(s)
        self.testkey(key2, randfunc, verbose)
        if verbose: print


    def check_rsa(self):
        "Check RSA algorithm"
        self.exercise(self.pool.get_bytes, RSA)

    def check_dsa(self):
        "Check DSA algorithm"
        self.exercise(self.pool.get_bytes, DSA)

    def check_elgamal(self):
        "Check ElGamal algorithm"
        self.exercise(self.pool.get_bytes, ElGamal)

    def check_qnew(self):
        "Check qNEW algorithm"
        self.exercise(self.pool.get_bytes, qNEW)
Example #39
0
 def __init__(self):
     self._wr = RandomPool()
     self.randomize()
from Crypto.PublicKey import RSA
from Crypto import Random
from Crypto.Util.randpool import RandomPool
"""
rng = Random.new().read
RSAkey = RSA.generate(1024, rng)

"""
pool = RandomPool(1024)
pool.stir()
randfunc = pool.get_bytes
RSAkey = RSA.generate(1024, randfunc)

f = open("meter-private.pem", "w+")
f.write(RSAkey.exportKey("PEM"))
f.close()
print "Gerou chave Privada"
f = open("meter-public", "w+")
f.write(RSAkey.publickey().exportKey("PEM"))
f.close()
print "Gerou chave Publica"
Example #41
0
 def __init__(self):
     from Crypto.Util.randpool import RandomPool
     self.RandomPool = RandomPool()
Example #42
0
 def __init__(self):
     from Crypto.Util.randpool import RandomPool
     self.RandomPool = RandomPool()
Example #43
0
from Crypto.PublicKey import RSA
from Crypto.Util.randpool import RandomPool
 
texto = "texto a encriptar"

# Você deve usar a melhor fonte de dados aleatórios que tiver à
# disposição. Pra manter o exemplo mais portável, usaremos o
# RandomPool do próprio PyCrypto:
 
pool = RandomPool(384)
pool.stir()

# randfunc(n) deve retornar uma string de dados aleatórios de
# comprimento n, no caso de RandomPool, o método get_bytes
randfunc = pool.get_bytes

# Se tiver uma fonte segura (como /dev/urandom em sistemas unix), ela
# deve ser usada ao invés de RandomPool

# pool = open("/dev/urandom")
# randfunc = pool.read
 
# Tamanho da chave, em bits
N = 2048
 
# O algoritmo RSA usado aqui não utiliza K, que pode ser uma string
# nula.
K = None

# Geramos a chave (contendo a chave pública e privada):
key = RSA.generate(N, randfunc)
Example #44
0
 def setup (self):
     # Set up a random pool; we won't bother to actually fill it with
     # entropy from the keyboard
     self.pool = RandomPool(384)
     self.pool.stir()
Example #45
0
#!/usr/bin/env python

# Script to time fast and slow RSA operations
# Contributed by Joris Bontje.

import time, pprint
from Crypto.PublicKey import *
from Crypto.Util.randpool import RandomPool
from Crypto.Util import number

pool = RandomPool()
pool.stir()

KEYSIZE=2048
COUNT=5
fasttime=0
slowtime=0
for x in range(COUNT):
    begintime=time.time()
    rsa=RSA.generate(KEYSIZE, pool.get_bytes)
    endtime=time.time()
    print "Server: Generating %d bit RSA key: %f s" % (KEYSIZE, endtime-begintime)
    rsa_slow=RSA.construct((rsa.n,rsa.e,rsa.d))

    code=number.getRandomNumber(256, pool.get_bytes)
    begintime=time.time()
    signature=rsa.sign(code,None)[0]
    endtime=time.time()
    fast=(endtime-begintime)
    fasttime=fasttime+fast
    print "Fast signing took %f s" % fast
Example #46
0
from Crypto.PublicKey import RSA
from Crypto import Random
from Crypto.Util.randpool import RandomPool
"""
rng = Random.new().read
RSAkey = RSA.generate(1024, rng)

"""
bits = 1024

pool = RandomPool(bits)
pool.stir()
randfunc = pool.get_bytes
RSAkey = RSA.generate(bits, randfunc)

f = open("inmetro-private.pem", "w+")
f.write(RSAkey.exportKey("PEM"))
f.close()
print "Gerou chave Privada"
f = open("inmetro-public", "w+")
f.write(RSAkey.publickey().exportKey("PEM"))
f.close()
print "Gerou chave Publica"
def geraChave():
    pool = RandomPool(1024)
    pool.stir()
    randfunc = pool.get_bytes
    key = RSA.generate(1024, randfunc)
    return key
Example #48
0
def generateRandom(n):
    atfork()
    rand = RandomPool()  # using seperate instance of RandomPool purposely
    return rand.get_bytes(n)
Example #49
0
 def generate_key_string(cls, key_size=256):
     key = RandomPool(512).get_bytes(key_size / 8 + SIG_SIZE)
     return key.encode("base64").replace("\n", "")
Example #50
0
	def create(self, file, cipherName, cipherMode, hashSpec, masterSize, stripes):
		"""Initializes the file class passed in with the LUKS header

        	Parameters
		   cipherName: aes, cast5, blowfish
		   cipherMode: cbc-plain, cbc-essiv:<hash>
		   hashSpec: sha1, sha256, md5, ripemd160
		   masterSize: length of the master key in bytes (must match cipher)
		   stripes: number of stripes when Af Splitting keys

		For compatibility with the Linux kernel dm-crypt, hashSpec must equal "sha1"

		cbc-plain uses the sector number as the IV.  This has a weakness: an attacker
		may be able to detect the existance of watermarked files.
		cbc-essiv:<hash> protects against the weakness in cbc-plain, but is 
		slightly slower. The digest size of the hash function passed to cbc-essiv
		must match the key size of the cipher.  
		aes-cbc-essiv:sha256 works, while aes-cbc-essiv:sha1 does not

		For more information about the details of the attacks and risk assesment, see
		http://clemens.endorphin.org/LinuxHDEncSettings
		"""

		if self.file != None:
			raise "This LuksFile has already been initialized"

		self._check_cipher(cipherName, cipherMode)

		self.magic = self.LUKS_MAGIC
		self.version = 1
		self.mkDigestIterations = 10
		self.keyBytes = masterSize
		self.hashSpec = hashSpec

		rand = RandomPool(self.SALT_SIZE + 16 + masterSize)

		# Generate the salt
		self.mkDigestSalt = rand.get_bytes(self.SALT_SIZE)

		# Generate a random master key
		self.masterKey = rand.get_bytes(self.keyBytes)
		self.ivGen.set_key(self.masterKey)

		# generate the master key digest
		pbkdf = PBKDFv2.PBKDFv2()
		self.mkDigest = pbkdf.makeKey(self.masterKey, self.mkDigestSalt, self.mkDigestIterations, hashlib.new(self.hashSpec).digest_size, self.hashSpec)

		# init the key information
		currentSector = math.ceil(592.0 / self.SECTOR_SIZE)
		alignSectors = 4096 / self.SECTOR_SIZE
		blocksPerStripe = math.ceil(float(self.keyBytes * stripes) / self.SECTOR_SIZE)

		self.keys = [None] * 8
		for i in range(0, 8):
			if currentSector % alignSectors > 0:
				currentSector += alignSectors - currentSector % alignSectors
			self.keys[i] = self._key_block()
			self.keys[i].create(currentSector, stripes, self.LUKS_KEY_DISABLED)
			currentSector += blocksPerStripe

		# Set the data offset
		if currentSector % alignSectors > 0:
			currentSector += alignSectors - currentSector % alignSectors
		self.payloadOffset = currentSector

		# Generate a UUID for this file
		self._uuidgen(rand)

		# Create a new file, and save the header into it
		self.file = file
		self._save_header()

		# Write FF into all the key slots
		FFData = "\xFF" * int(self.SECTOR_SIZE)
		for i in range(0, 8):
			self.file.seek(int(self.keys[i].keyMaterialOffset))
			for sector in range(0, int(blocksPerStripe)):
				self.file.write(FFData)

		# Flush the file to disk
		try:
			self.file.flush()
			os.fsync(self.file.fileno())
		except:
			# We might get an error because self.file.fileno() does not exist on StringIO
			pass
Example #51
0
	def set_key(self, keyIndex, password, iterations, checkMinStripes=0):
		"""Sets the key block at keyIndex using password

		Sets the key block at keyIndex using password, hashed iterations
		times using PBKDFv2 (RFC2104).  This LuksFile must be unlocked by
		calling open_any_key() before calling this function.
		checkMinStripes is used to detect basic header manipulation, since
		the number of stripes for the key is set by create(), before
		we write a password to disk we make sure the key is not weak because
		of a small number of stripes.

		This function will raise an error if the key is already enabled.
		"""

		# Some checks
		if self.masterKey == None:
			raise "A key has not been unlocked.  Call open_any_key() first."

		if keyIndex < 0 or keyIndex > 7:
			raise "keyIndex out of range"

		key = self.keys[keyIndex]
		if key.active != self.LUKS_KEY_DISABLED:
			raise "Key is active.  Delete the key and try again"

		if checkMinStripes == 0: checkMinStripes = self.KEY_STRIPES
		if key.stripes < checkMinStripes:
			raise "Key section %i contains too few stripes.  Header manipulation?" % keyIndex

		key.passwordIterations = iterations

		# Generate a random salt for this key
		rand = RandomPool(self.SALT_SIZE)
		key.passwordSalt = rand.get_bytes(self.SALT_SIZE)

		# Hash the key using PBKDFv2
		pbkdf = PBKDFv2.PBKDFv2()
		derived_key = pbkdf.makeKey(password, key.passwordSalt, key.passwordIterations, self.keyBytes, self.hashSpec)

		# Split the key into key.stripes
		AfKey = AfSplitter.AFSplit(self.masterKey, key.stripes, self.hashSpec)

		AfKeySize = len(AfKey)
		if AfKeySize != key.stripes * self.keyBytes:
			raise "ERROR: AFSplit did not return the correct length of key"

		# Set the key for IV generation
		self.ivGen.set_key(derived_key)

		# Encrypt the splitted key using the hashed password
		AfSectors = int(math.ceil(float(AfKeySize) / self.SECTOR_SIZE))
		for sector in range(0, AfSectors):
			self._encrypt_sector(derived_key, key.keyMaterialOffset + sector, sector, \
                               AfKey[int(sector*self.SECTOR_SIZE):int((sector+1)*self.SECTOR_SIZE)])

		key.active = self.LUKS_KEY_ENABLED

		# Reset the key used for to IV generation in data mode
		self.ivGen.set_key(self.masterKey)

		self._save_header()
Example #52
0
class Client:

    def __init__(self):
        print "Loading config...",
        # Mode "U" for universal newlines, so \r\n is okay
        self.config = eval("".join(open(config_file, "rU").read()))
        print "OK"

        if self.config.has_key("myip"):
            if self.config["myip"] != "":
                self.myip = self.config["myip"]
            else:
                self.myip = get_default_ip()
                print "Using IP: ", self.myip
        else:
            print "IP not specified, getting network interface list..."

            # Look for an up interface. Use get_ifaces instead of just the
            # IP so we can also get the netmask, too
            ifaces = get_ifaces()
            for name in ifaces:
                if not ifaces[name].has_key("status") or \
                   ifaces[name]["status"] != True and \
                   ifaces[name]["status"] != "active":
                    continue
                if not ifaces[name]["inet"]: continue

                print name,ifaces[name]["inet"],ifaces[name]["netmask"]
            # XXX: This is a problem for wxfer.py! It needs input! This is
            # how it should be, though. Chuck popen into the trash.
            print "Which interface? ",
            i = sys.stdin.readline()[:-1]
            print "Using IP ", ifaces[i]["inet"]
            self.myip = ifaces[i]["inet"]
            self.netmask = ifaces[i]["netmask"]   # save for later
            self.netmask = int(ifaces[i]["mtu"]) - 28

        if self.config.has_key("myport"):
            self.myport = self.config["myport"]
        else:
            print "defaulting to port 41170"
            self.myport = 41170

        # Your local IP to bind to. This can be your private IP if you're behind
        # a NAT it can be the same as "myip", or it can be "" meaning bind to
        # all ifaces
        self.localaddr = ""

        self.senders = {}

        if self.config.has_key("irc_nick"):
            self.irc_nick = self.config["irc_nick"]
        else:
            print "No IRC nick specified. What to use? "
            self.irc_nick = sys.stdin.readline()[:-1]
       
        if self.config.has_key("irc_name"):
            self.irc_name = self.config["irc_name"]
        else:
            self.irc_name = self.irc_nick

        if self.config.has_key("mss"):
            self.mss = self.config["mss"]
        else:
            try:
                self.mss
            except:
                print "MSS not found! Please set it."
                raise SystemExit        
   
        if self.config.has_key("rwinsz"):
            self.rwinsz = self.config["rwinsz"]
            self.rwinsz_old = 0
                                  #RWINSZ never changes here! TODO:if it does,
                                  # then rwinsz_old MUST be updated to reflect.
        else:
            print "Please set rwinsz"
            raise SystemExit 

        if self.config.has_key("bandwidth"):
            self.bandwidth = self.config["bandwidth"]
        else:
            print "Please set bandwidth"
            sys.exit(5)

        self.set_callback(self.default_cb)   # override me please

    def on_msg(self, nick, msg):
        """Handle incoming messages."""
        print "<%s> %s" % (nick, msg)
        # This isn't used anymore - its in the auth packet instead
        if (msg.find("sumi start ") == 0):
            args = unpack_args(msg[len("sumi start "):])
            (filename, offset, size) = (args["f"], args["o"], args["l"])

            offset = int(offset)
            size = int(size)

            if (self.senders.has_key(nick)):
                self.sendmsg(nick, "n%d" % self.rwinsz)
                self.rwinsz_old = self.rwinsz
                print "Starting n%d %s for %s,%d,%d" % (self.rwinsz, nick,
                    filename, offset, size)
            else:
                print "ERROR: user not known, stranger trying to sumi start!"
                print "Senders: ", self.senders
        elif (msg.find("error: ") == 0):
            errmsg = msg[len("error: "):]
            print "*** Error: ", errmsg

    # Write the resume file for transfer from nick
    def save_lost(self, x):
        lost = ",".join(map(str, self.senders[x]["lost"].keys()))
        lost += "," + str(self.senders[x]["at"])   # last is at, cur/last
        if (lost != ""):
            self.senders[x]["fs"].seek(0)
            self.senders[x]["fs"].truncate()
            self.senders[x]["fs"].flush()
            self.senders[x]["fs"].write(lost)
            self.senders[x]["fs"].flush()
            #print "WROTE LOST: ",lost

    def handle_packet(self, data, addr):
        """Handle received packets."""
        prefix  = data[:3]
        (seqno, ) = struct.unpack("!L", "\0" + data[3:6])
 
        # Find nick that is associated with the random prefix; which is the
        # only way to identify the source.
        # The data structures aren't setup very efficiently
        nick = None
        for x in self.senders:
            if self.senders[x].has_key("prefix") and \
               self.senders[x]["prefix"] == prefix:
                nick = x
                break
        if nick == None:
            print "DATA:UNKNOWN PREFIX!",len(data),"bytes from",addr
            return
        #print "Incoming:",len(data),"bytes from",addr,"=",nick," #",seqno

        self.senders[nick]["retries"] = 0   # acks worked
 
        self.senders[nick]["last_msg"] = time.time()

        # XXX: Resuming sometimes asks for packets more than once, fix it.
        #     Maybe the dupe could be compared to see if any errors?
        # Last most recently received packet, for resuming
        self.senders[nick]["at"] = seqno 
        # Sequence number is 3 bytes in the SUMI header in network order
        # (so a null can easily be prepended for conversion to a long),
        # this used to be partially stored in the source port, but PAT--
        # Port Address Translation--closely related to NAT, can mangle 
        # the srcport
        if (seqno == 0):       # all 0's = auth packet
            context = md5.md5()
            context.update(data)       # auth "key" is all of data, hash it
            #context.update("hi")#bad hash
            #hash = context.hexdigest() 
            hash = base64.encodestring(context.digest())[:-1]
            print "PKT:Got auth packet from",addr," for ",nick,
  
            print "PKT:Verifying prefix (authenticity of server)..."

            # XXX: Does this ever fail?
            if (data[0:3] == prefix and len(data) > len(prefix)):
                print "OK\n"
            else:
                print "failed!"

            # file metadata should be here (file length)
            (self.senders[nick]["size"], ) = struct.unpack("!L", 
                data[SUMIHDRSZ:SUMIHDRSZ + SUMIAUTHHDRSZ])
            print "SIZE:%d" % (self.senders[nick]["size"],)
            filename=data[SUMIHDRSZ+4:data[SUMIHDRSZ+4:].find("\0")+SUMIHDRSZ+4]

            self.senders[nick]["fn"] = filename
            print "Filename: <%s>" % filename   
            self.callback(nick, "info", self.senders[nick]["size"], \
                base64.encodestring(prefix)[:-1], filename, \
                self.senders[nick]["transport"], \
                self.config["data_chan_type"])

            if (self.mss != len(data)):
                print "WARNING: Downgrading MSS %d->%d, maybe set it lower?" % (self.mss, len(data))
                self.mss = len(data)
                if (self.mss < 256):
                    print "MSS is extremely low (%d), quitting" % self.mss
                    sys.exit(-1)

            # Open the file and set it up
            if not self.senders[nick].has_key("fh"):  #  file not open yet
                print "Opening tempout for %s..." % nick,
                self.senders[nick]["start"] = time.time()

                # These try/except blocks try to open the file rb+, but if
                # it fails with 'no such file', create them with wb+ and
                # open with rb+. Good candidate for a function!
                try:
                    self.senders[nick]["fh"] = open(self.config["dl_dir"] + \
                         self.senders[nick]["fn"], "rb+")  
                except IOError:
                    open(self.config["dl_dir"] + \
                        self.senders[nick]["fn"], "wb+").close()
                    self.senders[nick]["fh"] = open(self.config["dl_dir"] + \
                        self.senders[nick]["fn"], "rb+")
                print "open"

                # Open a new resuming file (create if needed)
                try:
                    self.senders[nick]["fs"] = open(self.config["dl_dir"] + \
                        self.senders[nick]["fn"] + ".lost", "rb+")   
                    is_resuming = 1  # unless proven otherwise
                except IOError:
                    open(self.config["dl_dir"] + \
                        self.senders[nick]["fn"] + ".lost", "wb+").close()
                    self.senders[nick]["fs"] = open(self.config["dl_dir"] + \
                        self.senders[nick]["fn"] + ".lost", "rb+")
                    is_resuming = 0   # empty resume file

                # Check if the data file exists, and if so, resume off it
                lostdata = None

                if (os.access(self.config["dl_dir"] + \
                    self.senders[nick]["fn"], os.R_OK)):
                   # The data file is readable, read lost data 
                    lostdata = self.senders[nick]["fs"].read().split(",")

                    # If the below is true, the xfer is complete--",X".
                    # TODO: Let user overwrite or cancel. Needs to have
                    # a better interface for this, GUI-able.
                    if (len(lostdata) == 2 and lostdata[0] == "" \
                        and int(lostdata[1]) == lostdata[1]):
                        is_resuming = 0
                        print self.senders[nick]["fn"] + " is finished!" + \
                              " It will not be resumed."
                        sys.exit(1)
                else: 
                    is_resuming = 0
                if (len(lostdata) <= 1): is_resuming = 0
                print "LEN LOSTDATA=",len(lostdata)

                is_resuming=0#FORCE
 
                # Setup lost
                if (is_resuming):   # this works
                    self.senders[nick]["at"] = int(lostdata.pop())
                    if (len(lostdata) == 0 or len(lostdata[0]) == 0):
                        # Several ways to do this. a) Go through the normal
                        #  process, and finish there. con: auth. pro: simple?
                        #  b) save user the time, finished. c) overwrite choice
                        print "File complete, not resumed"

                        # Right now, it finishes the transfer.
                        self.callback(nick, "fin", 0, \
                            self.senders[nick]["size"], \
                            0, "")

                        # TODO: give choice
                        #self.cb("overwrite?", self.senders[nick]["fn"]
                        #sys.exit(1)
                        return #XYZ
                    print "RESUMING"
                    print "IS_RESUMING: LOST: ",lostdata
                    self.senders[nick]["lost"] = {}
                    for x in lostdata:
                        try:
                            self.senders[nick]["lost"][int(x)] = 1
                        except ValueError:
                            pass    # don't add non-ints
                    print "LOADED LOSTS:",self.senders[nick]["lost"]

                    # Initialize the rwin with empty hashes, mark off missings
                    self.senders[nick]["rwin"] = {}
                    for x in range(1, self.senders[nick]["at"]):
                        self.senders[nick]["rwin"][int(x)] = 1   # received 
                    for L in self.senders[nick]["rwin"]:    # mark losses
                        self.senders[nick]["rwin"][int(L)] = 0

                    # Bytes received = (MSS * at) - (MSS * numlost)
# TODO: Fix error in reporting number of bytes received, off by about 16,
# even though it is saved correctly...this leads to >100% progress rates
                    # XXX: MSS's may be inconsistant across users! Corruption
                    self.senders[nick]["bytes"] = \
                        (self.mss * self.senders[nick]["at"]) - \
                        (self.mss * len(self.senders[nick]["lost"].keys()))

                    # Files don't store statistics like these
                    self.senders[nick]["all_lost"] = []  # blah
                    self.senders[nick]["rexmits"] = 0
                else:
                    # Initialize
                    self.senders[nick]["at"] = 0
                    self.senders[nick]["rexmits"] = 0
                    self.senders[nick]["all_lost"] = []
                    self.senders[nick]["bytes"] = 0  # bytes received
                    self.senders[nick]["lost"] = {}    # use: keys(), pop()..
    # RWIN is a list of all the packets, and if they occured (0=no),
    # incremented each time a packet of that seqno is received. Since
    # Python arrays don't automatically grow with assignment, a hash
    # is used instead. If "rwin" was an array, [], missed packets would
    # cause an IndexError. See
    #http://mail.python.org/pipermail/python-list/2003-May/165484.html
                # for rationale and some other class implementations
                    self.senders[nick]["rwin"] = {}


            # Tell the sender to start sending, we're ok
            print "Sending sumi auth"
            self.sendmsg(nick, "sumi auth " + pack_args({"m":self.mss,
                "s":addr[0], "h":hash, "o":self.senders[nick]["at"]}))
            # The rest of this function handles data transfer
            return
        else:
            # Prefix has been checked, seqno calculated, so just get to the data
            data = data[SUMIHDRSZ:]

            # All file data is received here
  
            self.senders[nick]["last_msg"] = time.time()
   
            offset = (seqno - 1) * (self.mss - SUMIHDRSZ)
            self.senders[nick]["fh"].seek(offset)
            self.senders[nick]["fh"].write(data)
            #sys.stdout.write(".");
            #print "WRITE:%d:%d:%d:%s"%(offset, offset + len(data), len(data))
            #self.callback(nick, "write", offset, offset + len(data), len(data), \
                #self.senders[nick]["size"], addr)
 
            self.senders[nick]["bytes"] += len(data)   # correct

            self.callback(nick, "write", offset, self.senders[nick]["bytes"],
                self.senders[nick]["size"], addr)

            # Mark down each packet in our receive window
            try:
                self.senders[nick]["rwin"][seqno] += 1
            except KeyError:
                self.senders[nick]["rwin"][seqno] = 1    # create
 
            if (self.senders[nick]["rwin"][seqno] >= 2):
                print "(DUPLICATE PACKET %d, IGNORED)" % seqno
                return
 
            #Check previous packets, see if they were lost (unless first packet)
            if (seqno > 1):
                i = 1 
                while 1:
                    if (not self.senders[nick]["rwin"].has_key(seqno - i)):
                        self.senders[nick]["lost"][seqno - i] = 1
                        self.senders[nick]["all_lost"].append(str(seqno - i))
                        i += 1
                    else:
                        break  # this one wasn't lost, so already checked
    
                if self.senders[nick]["lost"].has_key(seqno):
                    self.senders[nick]["lost"].pop(seqno)
                    print "Recovered packet ", seqno, self.senders[nick]["lost"]
                    self.senders[nick]["rexmits"] += 1
                    print "(rexmits = ", self.senders[nick]["rexmits"]
                    self.callback(nick, "rexmits", self.senders[nick]["rexmits"])
                    #on_timer()   # Maybe its all we need

            if (self.senders.has_key(nick) and len(self.senders[nick]["lost"])):
                self.callback(nick, "lost", self.senders[nick]["lost"].keys())
                #print "These packets are currently lost: ", self.senders[nick]["lost"].keys()
                self.save_lost(nick)
            else:
                self.callback(nick, "lost", ())

        # Less than full sized packet = last
        if (len(data) != self.mss - SUMIHDRSZ):
            print "NON-FULLSIZED: %d != %d" % (len(data), self.mss - SUMIHDRSZ)
            self.senders[nick]["gotlast"] = 1
            # File size is now sent in auth packet so no need to calc it here
            #self.senders[nick]["size"] = self.senders[nick]["fh"].tell()
            self.on_timer()     # have it check if finished

    def thread_timer(self):
        """Every RWINSZ seconds, send a nak of missing pkts up to that point."""
        while 1:
            time.sleep(self.rwinsz)
            self.on_timer()

    def on_timer(self):
        """Acknowledge to all senders and update bytes/second."""
        tmp_senders = self.senders.copy()
        for x in tmp_senders:
            if (not self.senders[x].has_key("lost")):  # not xfering yet
                self.senders[x]["retries"] = 0   # initialize
                continue

            # Worth trying to update bps here
            if self.senders[x].has_key("bytes"):
                if self.senders[x].has_key("last_bytes"):
                    bytes_per_rwinsz = \
                        self.senders[x]["bytes"] - self.senders[x]["last_bytes"]
          
                    rate = float(bytes_per_rwinsz) / float(self.rwinsz) 
                    # rate = delta_bytes / delta_time   (bytes arrived)
                    # eta = delta_bytes * rate          (bytes not arrived)
                    if (rate != 0):
                        eta = (self.senders[x]["size"] - self.senders[x]["bytes"]) / rate
                    else:
                        eta = 0
                    # Callback gets raw bits/sec and seconds remaining
                    self.callback(x, "rate", rate, eta)
                    self.senders[x]["last_bytes"] = self.senders[x]["bytes"]
                else:
                    self.senders[x]["last_bytes"] = self.senders[x]["bytes"]

            if (len(self.senders[x]["lost"]) == 0 and 
                self.senders[x].has_key("gotlast")):
                return self.finish_xfer(x) # there's nothing left, we're done!
            try:
                # Some missing packets, finish it up
                lost = ",".join(map(str, self.senders[x]["lost"].keys()))
                # Compress by omitting redundant elements to ease bandwidth
                if (self.rwinsz_old == self.rwinsz and lost == ""):
                    self.sendmsg(x, "n")
                elif (lost == ""):
                    self.sendmsg(x, "n%d" % self.rwinsz)
                else:
                    self.sendmsg(x, ("n%d," % self.rwinsz) + lost)

                self.senders[x]["retries"] += 1
                if (self.senders[x]["retries"] > 5):
                    print x,"exceeded maximum retries (5), cancelling"
                    self.senders.pop(x)
                    self.callback(x, "timeout")

                self.rwinsz_old = self.rwinsz# TODO: update if changes..but need
                                          # to give the win on first(right)

            except KeyError:   # sender ceased existance
                pass

    def finish_xfer(self, nick):
        """Finish the file transfer."""

        # Nothing lost anymore, update. Saved as ",X" where X = last packet.
        print "DONE - UPDATING"
        self.save_lost(nick)

        # If was encrypted, decrypt
        # TODO: Separate transport and dchan encryption types
        if (self.config["crypto"] == "s"):
            #from aes.aes import aes
            from Crypto.Cipher import AES

            self.callback(nick, "dec", "AES")
            #aes_crypto = aes()
            #aes_crypto.setKey(self.config["passwd"])
            # Use CFB mode because it doesn't require padding
            aes_crypto = AES.new(self.config["passwd"], AES.MODE_CFB)

            # Error: I/O operation on closed file?
            self.senders[nick]["fh"].flush()
            self.senders[nick]["fh"].seek(0)
            data = self.senders[nick]["fh"].read()
 
            print "About to decrypt"+str(len(data))+"bytes" 
            data = aes_crypto.decrypt(data)

            out = open(self.config["dl_dir"] + self.senders[nick]["fn"], "wb")
            out.write(data)
            self.senders[nick]["fh"] = out

        self.sendmsg(nick, "sumi done")

        duration = time.time() - self.senders[nick]["start"]
        self.senders[nick]["fh"].close()
        self.callback(nick, "fin", duration, self.senders[nick]["size"], \
              self.senders[nick]["size"] / duration / 1024, \
              self.senders[nick]["all_lost"])
        
        #print "Transfer complete in %.6f seconds" % (duration)
        #print "All lost packets: ", self.senders[nick]["all_lost"]
        #print str(self.senders[nick]["size"]) + " at " + str(
        #     self.senders[nick]["size"] / duration / 1024) + " KB/s"
        self.senders.pop(nick)    # delete the server key
        sys.exit(0) # here now for one file xfer per program

    def thread_recv_packets(self):
        """Receive anonymous packets."""
        print "THREAD 1 - PACKET RECV"
        if (self.config["data_chan_type"] == "u"):
            self.server_udp()
        elif (self.config["data_chan_type"] == "e"):
            self.server_icmp()
        elif (self.config["data_chan_type"] == "i"):
            self.server_icmp()

    def server_icmp(self):
        """Receive ICMP packets. Requires raw sockets."""
        print "ICMP started."   # At the moment, needs to be ran as root
        #print "UID=", os.getuid()
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, \
                             socket.IPPROTO_ICMP)
        # XXX: TODO: Fix ICMP. The server doesn't generate ICMP checksums,
        # so we won't be able to receive here!
        sock.bind((self.localaddr, 0))
        while 1:
            (data, addr) = sock.recvfrom(65535)
            data = data[20 + 8:]     # IPHDRSZ + ICMPHDRSZ, get to payload
            self.handle_packet(data, addr)

    def server_udp(self):
        """Receive UDP packets."""
        print "UDP started."
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        while 1:
            try:
                sock.bind((self.localaddr, self.myport))
            except socket.error:
                failed = 0
                if (sys.exc_info()[1].args[0] == 48):
                    print "Port",self.myport,"in use, trying next"
                    self.myport += 1
                    failed = 1
                if not failed: break
        print "Bound to ", self.myport
 
        while 1:
            # This is interrupted...?
            try:
                (data, addr) = sock.recvfrom(65535)
            except socket.error:
                if sys.exc_info()[1].args[0] != 4: # Interrupted system call
                    raise sys.exc_info()[1]     # not for us to catch 
                # Reinvoke it
                continue 
            self.handle_packet(data, addr)

    def cli_user_input(self):
        """Client user input (not used anymore), belongs in separate program."""
        input_lock.acquire()   # wait for messaging program to be connected
        print "Started user input thread... you may now type"
        while 1:
            line = sys.stdin.readline()
            if line == "":    # EOF, exit
                return 0
            line = line[:-1]  # Strip \n
            if line == "":    # blank line (\n), ignore
                continue
            args = line.split()
            if (args[0] == "/get"):
                try:
                    self.request(args[1], args[2])
                except IndexError:
                    print "Usage: get <server_nick> <file>"
            else:
                self.sendmsg(irc_chan, line)
    # DO SUMI SEC THEN ENCRYPT MSGS & PACKETS
        # Pre-auth. aes'd sumi send > irc_maxlen
        # MAX IRC PRIVMSG IN XCHAT: 452 in #sumi, 454 in #a (??) 462 in #a*31
        # ON NGIRCD: COMMAND_LEN - 1, is 513-1 is 512. Room for PRIVMSG+nick.
        # ":jeff PRIVMSG " = 14
        # Continuations are now implemented in some transports (segment()),
        # TODO: Also, think about combining some elements of sumi send with
        # sumi sec. Consider making sumi sec handle the auth packet, and
        # sumi send deal strictly with file transfers. This way, sumi sec+
        # sumi login can be implemented later; allowing remote admin.
        # TODO: Actually, why not simply extend sumi send to allow remote admn.
    def secure_chan(self, server_nick):
        """Request a secure channel."""
        if (self.config["crypto"] == "a"):
            # TODO: This key generation should be done elsewhere and better
            from Crypto.PublicKey import RSA
            from Crypto.Util.randpool import RandomPool
            from Crypto.Util import number             
            self.pool = RandomPool(384)
            self.pool.stir()
            # Larger key needed to encrypt larger data, 768 too small
            print "Generating key..."
            import cPickle
            # Only send public key, not private key
            # TODO: this needs to be fixed, its not seamless
            self.config["passwd"] = \
                cPickle.dumps(RSA.generate(1024, self.pool.get_bytes).publickey())

        msg = "sumi sec " + \
            self.config["crypto"] + \
            base64.encodestring(self.config["passwd"]).replace("\n", "")

        # Bootstrap sendmsg 
        #self.sendmsg(server_nick, msg)
        self.senders[server_nick]["sendmsg"](server_nick, msg)
        # Now, communicate in crypto with server_nick
        self.senders[server_nick]["crypto"] = self.config["crypto"]
        self.senders[server_nick]["passwd"] = self.config["passwd"]

#    def sendmsg(self, nick, msg):
#        """Send a message over the covert channel using loaded module."""
#        #print "SENDING |%s| to |%s|" % (msg, nick)
#        #return sendmsg(nick, msg)
#        return self.senders[nick]["sendmsg"](nick, msg)

    # Send a secure message to server_nick
    def sendmsg(self, server_nick, msg):
        is_enc = 0
        #print "===", self.senders[server_nick]
        print ">>%s>%s" % (server_nick, msg)
        if (self.senders.has_key(server_nick) and \
            self.senders[server_nick]["crypto"] == "s"):
            from Crypto.Cipher import AES
            #from aes.aes import aes
            #aes_crypto = aes()
            #aes_crypto.setKey(self.senders[server_nick]["passwd"])
            #msg = aes_crypto.encrypt(msg)
            aes_crypto = AES.new(self.senders[server_nick]["passwd"], AES.MODE_CFB)
            msg = aes_crypto.encrypt(msg)
            is_enc = 1
        elif (self.senders.has_key(server_nick) and \
              self.senders[server_nick]["crypto"] == "a"):
            import cPickle
            from Crypto.PublicKey import RSA
            key = cPickle.loads(self.config["passwd"])
            msg = key.encrypt(msg, number.getPrime(10, self.pool.get_bytes))[0]
            is_enc = 1

        # If encrypted, base64 it for transport
        if is_enc:
            msg = base64.encodestring(msg)
            # base64 likes to split the lines, remove newlines we'll do it
            # ourself thanks
            msg = msg.replace("\n", "")

        #print "<<<<<<%s>>>>>>" % msg
        # Note, this message will usually be long; the transport takes
        # care of splitting it up for us if necessary
        ##self.sendmsg(server_nick, msg)
        return self.senders[server_nick]["sendmsg"](server_nick, msg)
       
    def request(self, transport, server_nick, file):
        """Request a file from a server."""
        global transports

        # command line args are now the sole form of user input;
        self.callback(server_nick, "t_wait")   # transport waiting, see below

        # Input lock is mostly obsolete -- it is supposed to wait for
        # transport_init() to return, but we already wait for it 
        #input_lock.acquire()   # wait for transport connection

        if (self.senders.has_key(server_nick)):
            print "Already have a transfer from ",server_nick
            return

        self.senders[server_nick] = {} 

        # Setup transport system
        self.senders[server_nick]["transport"] = transport
        self.load_transport(transport, server_nick)
        if (transports.has_key(transport) and transports[transport]):
            pass    # already initialized
            print "Not initing ",transport
        else:
            self.senders[server_nick]["transport_init"]()
            transports[transport] = 1   # Initialize only once
            print "Just inited",transport

        # Setup cryptology
        self.secure_chan(server_nick)

        print "You want %s from %s" % (server_nick, file)

        offset = 0
        prefix = string.join(map(chr, (random.randint(0, 255),
                                       random.randint(0, 255),
                                       random.randint(0, 255))), "")
 
        self.senders[server_nick]["prefix"] = prefix

        msg = "sumi send " + pack_args({"f":file,
            "o":offset, "i":self.myip, "n":self.myport, "m":self.mss,
            "p":base64.encodestring(prefix)[:-1], "b":self.bandwidth,
            "w":self.rwinsz, "d":self.config["data_chan_type"],
            "x":self.config["crypto"]})
            # XYZ: In sumi sec
            #"K":base64.encodestring(self.config["passwd"])[:-1]})


        self.sendmsg(server_nick, msg) 
        #self.sendmsg(server_nick, msg)
        print "Sent"
        self.callback(server_nick, "req_sent") # request sent (handshaking)

        # Countdown. This provides a timeout for handshaking with nonexistant
        # senders, so the user isn't left hanging.
        maxwait = self.config["maxwait"]

        for x in range(maxwait, 0, -1):
            # If received fn in this time, then exists, so stop countdown
            if (self.senders[server_nick].has_key("fn")):
                return      # don't break - otherwise will timeout
            self.callback(server_nick, "req_count", x)
            time.sleep(1)

        self.callback(server_nick, "timeout")

    # The sole request. In a separate thread so it can wait for IRC.
    # NOTE, sumigetw doesn't use this, it makes its own thread & calls request
    def thread_request(self, nick, file):
         self.request(nick, file)

    def set_callback(self, f):
        """Set callback to be used for handling notifications."""
        self.callback = f

    def default_cb(self, cmd, *args):
        print "(CB)" + cmd + ":" + ",".join(list(map(str, args)))

    def load_transport(self, transport, nick):
        global input_lock, sendmsg, transport_init
        # Import the transport. This may fail, if, for example, there is
        # no such transport module.
        print sys.path
        try:
            t = __import__("transport.mod" + transport, None, None,
                           ["transport_init", "sendmsg"])
        except ImportError:
            self.callback(nick, "t_fail", sys.exc_info())
            return

        t.segment = segment

        self.senders[nick]["sendmsg"] = t.sendmsg
        #sendmsg = t.sendmsg
        #transport_init = t.transport_init

        #self.transport_init = transport_init

        self.senders[nick]["transport_init"] = t.transport_init

        # Wait for transport
        #input_lock.acquire()
   # moved to caller

    def main(self, transport, nick, file):

        #load_transport(transport)

        thread.start_new_thread(self.thread_timer, ())
        senders[nick]["transport_init"] = t.transport_init
        thread.start_new_thread(self.thread_request, (nick, file))

        # This thread will release() input_lock, letting thread_request to go
        #transport_init()

        print "RELEASED"
        input_lock.release()

        # Main thread is UDP server. There is no transport thread, its sendmsg
        self.thread_recv_packets()
   # start waiting before requesting

    def on_exit(self):    # GUI uses this on_exit
        print "Cleaning up..."
        import pprint

        savefile = open(config_file, "w")
        savefile.write("# Client configuration file\n")
        savefile.write("# Please note - ALL COMMENTS IN THIS FILE WILL BE DESTROYED\n")
        # ^ I place all comments in config.py.default instead, or the docs
        pprint.pprint(self.config, savefile)
        savefile.close()

        sys.exit()