Пример #1
0
    def __init__(self, cryptosystem, num_trustees, threshold, public_key_value,
                 verification_partial_public_keys):
        """
        Creates a new threshold public key. Should not be invoked directly.
        
        Instead of using this constructor from outside of PloneVoteCryptoLib, 
        please use ThresholdEncryptionSetUp.generate_public_key().
        
        Arguments:
            (see class attributes for cryptosystem, num_trustees and threshold)
            public_key_value::long        -- The actual value of the public key
                                (g^2P(0) mod p, see ThresholdEncryptionSetUp)
            verification_partial_public_keys::long[]
                    -- A series of "partial public keys" (g^P(i) for each 
                       trustee i), used for partial decryption verification.
                       Note that the key for trustee i must be on index i-1 of
                       the array.
        """
        PublicKey.__init__(self, cryptosystem, public_key_value)

        # Some checks:
        if (threshold > num_trustees):
            raise ValueError("Invalid parameters for the threshold public key:"\
                             " threshold must be smaller than the total number"\
                             " of trustees. Got num_trustees=%d, threshold=%d" \
                             % (num_trustees, threshold))

        if (len(verification_partial_public_keys) != num_trustees):
            raise ValueError("Invalid parameters for the threshold public key:"\
                             " a verification partial public for each trustee "\
                             "must be included.")

        self.num_trustees = num_trustees
        self.threshold = threshold
        self._partial_public_keys = verification_partial_public_keys
Пример #2
0
 def __init__(self, cryptosystem, num_trustees, threshold, 
              public_key_value, verification_partial_public_keys):
     """
     Creates a new threshold public key. Should not be invoked directly.
     
     Instead of using this constructor from outside of PloneVoteCryptoLib, 
     please use ThresholdEncryptionSetUp.generate_public_key().
     
     Arguments:
         (see class attributes for cryptosystem, num_trustees and threshold)
         public_key_value::long        -- The actual value of the public key
                             (g^2P(0) mod p, see ThresholdEncryptionSetUp)
         verification_partial_public_keys::long[]
                 -- A series of "partial public keys" (g^P(i) for each 
                    trustee i), used for partial decryption verification.
                    Note that the key for trustee i must be on index i-1 of
                    the array.
     """
     PublicKey.__init__(self, cryptosystem, public_key_value)
     
     # Some checks:
     if(threshold > num_trustees):
         raise ValueError("Invalid parameters for the threshold public key:"\
                          " threshold must be smaller than the total number"\
                          " of trustees. Got num_trustees=%d, threshold=%d" \
                          % (num_trustees, threshold))
     
     if(len(verification_partial_public_keys) != num_trustees):
         raise ValueError("Invalid parameters for the threshold public key:"\
                          " a verification partial public for each trustee "\
                          "must be included.")
         
     self.num_trustees = num_trustees
     self.threshold = threshold
     self._partial_public_keys = verification_partial_public_keys
Пример #3
0
 def test_load_threshold(self):
     """
     Test that we can load a threshold public as a PublicKey object
     """
     file_path = os.path.join(os.path.dirname(__file__), 
                              "TestBasicEncryption.resources",
                              "test_threshold_pk.pvpubkey")
     
     recovered_key = PublicKey.from_file(file_path)
Пример #4
0
    def __init__(self, cryptosystem, private_key_value):
        """
        Creates a new private key. Should not be invoked directly.
        
        Instead of using this constructor from outside of PloneVoteCryptoLib, 
        please use the class methods EGCryptoSystem.new_key_pair() or 
        PrivateKey.from_file(file).
        
        Arguments:
            cryptosystem::EGCryptoSystem-- The ElGamal cryptosystem in which 
                                           this key is defined.
            private_key_value::long     -- The actual value of the private key.
        """
        public_key_value = pow(cryptosystem.get_generator(), private_key_value,
                               cryptosystem.get_prime())

        self.cryptosystem = cryptosystem
        self.public_key = PublicKey(cryptosystem, public_key_value)
        self._key = private_key_value
Пример #5
0
def run_tool(key_file, in_file, out_file):
    """
	Runs the plonevote.encrypt tool and encrypts in_file into out_file.
	"""
    # Load the public key
    print "Loading public key..."
    try:
        public_key = PublicKey.from_file(key_file)
    except InvalidPloneVoteCryptoFileError, e:
        print "Invalid public key file (%s): %s" % (key_file, e.msg)
        sys.exit(2)
Пример #6
0
def run_tool(key_file, in_file, out_file):
	"""
	Runs the plonevote.encrypt tool and encrypts in_file into out_file.
	"""
	# Load the public key
	print "Loading public key..."
	try:
		public_key = PublicKey.from_file(key_file)
	except InvalidPloneVoteCryptoFileError, e:
		print "Invalid public key file (%s): %s" % (key_file, e.msg)
		sys.exit(2)
Пример #7
0
 def __init__(self, cryptosystem, private_key_value):
     """
     Creates a new private key. Should not be invoked directly.
     
     Instead of using this constructor from outside of PloneVoteCryptoLib, 
     please use the class methods EGCryptoSystem.new_key_pair() or 
     PrivateKey.from_file(file).
     
     Arguments:
         cryptosystem::EGCryptoSystem-- The ElGamal cryptosystem in which 
                                        this key is defined.
         private_key_value::long     -- The actual value of the private key.
     """        
     public_key_value = pow(cryptosystem.get_generator(), 
                            private_key_value, 
                            cryptosystem.get_prime())
     
     self.cryptosystem = cryptosystem
     self.public_key = PublicKey(cryptosystem, public_key_value)
     self._key = private_key_value
Пример #8
0
 def test_save_load_file(self):
     """
     Test that we can correctly save a PublicKey to a file and load it 
     back. 
     """
     # Get a new public key object
     key = self.cryptosystem.new_key_pair().public_key
     
     # Get its fingerprint for comparison after deserialization
     original_fingerprint = key.get_fingerprint()
     
     # Get a temporary file object using tempfile
     (file_object, file_path) = tempfile.mkstemp()
     
     # We close the file descriptor since we will not be using it, instead 
     # PublicKey's methods take the filename and open/close the file as 
     # needed.
     # Note that using mkstemp() instead tempfile.TemporaryFile means the 
     # file remains in the filesystem even after it is closed.
     os.close(file_object)
     
     # Save the key using to_file(...)
     key.to_file(file_path)
     
     # Load it back using PublicKey.from_file(...)
     recovered_key = PublicKey.from_file(file_path)
                                      
     # Get the fingerprint of the recovered key
     recovered_fingerprint = recovered_key.get_fingerprint()
     
     # Check that the fingerprints match (and thus they're the same key)
     self.assertEqual(recovered_fingerprint, original_fingerprint)
     
     # Also check that the == operator recognizes them as equal
     self.assertEqual(recovered_key, key)
     self.assertFalse(recovered_key != key)
     
     # Delete the temporary file
     os.remove(file_path)
Пример #9
0
class PrivateKey:
    """
    An ElGamal private key object used for decryption.
    
    Attributes:
        cryptosystem::EGCryptoSystem    -- The ElGamal cryptosystem in which 
                                           this key is defined.
        public_key::PublicKey    -- The associated public key.
    """
    def __eq__(self, other):
        """
        Implements PrivateKey equality.
        """
        if (isinstance(other, PrivateKey)
                and (other.cryptosystem == self.cryptosystem)
                and (other.public_key == self.public_key)
                and (other._key == self._key)):
            return True
        else:
            return False

    def __ne__(self, other):
        """
        Implements PrivateKey inequality.
        """
        return not self.__eq__(other)

    def __init__(self, cryptosystem, private_key_value):
        """
        Creates a new private key. Should not be invoked directly.
        
        Instead of using this constructor from outside of PloneVoteCryptoLib, 
        please use the class methods EGCryptoSystem.new_key_pair() or 
        PrivateKey.from_file(file).
        
        Arguments:
            cryptosystem::EGCryptoSystem-- The ElGamal cryptosystem in which 
                                           this key is defined.
            private_key_value::long     -- The actual value of the private key.
        """
        public_key_value = pow(cryptosystem.get_generator(), private_key_value,
                               cryptosystem.get_prime())

        self.cryptosystem = cryptosystem
        self.public_key = PublicKey(cryptosystem, public_key_value)
        self._key = private_key_value

    def decrypt_to_bitstream(self, ciphertext, task_monitor=None, force=False):
        """
        Decrypts the given ciphertext into a bitstream.
        
        If the bitstream was originally encrypted with PublicKey.encrypt_X(), 
        then this method returns a bitstream following the format described 
        in Note 001 of the Ciphertext.py file:
            [size (64 bits) | message (size bits) | padding (X bits) ]
        
        Arguments:
            ciphertext::Ciphertext    -- An encrypted Ciphertext object.
            task_monitor::TaskMonitor    -- A task monitor for this task.
            force:bool    -- Set this to true if you wish to force a decryption 
                           attempt, even when the ciphertext's stored public key
                           fingerprint does not match that of the public key 
                           associated with this private key.
        
        Returns:
            bitstream::Bitstream    -- A bitstream containing the unencrypted 
                                       data.
        
        Throws:
            IncompatibleCiphertextError -- The given ciphertext does not appear 
                                           to be decryptable with the selected 
                                           private key.
        """
        # Check that the public key fingerprint stored in the ciphertext
        # matches the public key associated with this private key.
        if (not force):
            if (ciphertext.nbits != self.cryptosystem.get_nbits()):
                raise IncompatibleCiphertextError("The given ciphertext is " \
                        "not decryptable with the selected private key: " \
                        "incompatible cryptosystem/key sizes.")

            if (ciphertext.pk_fingerprint !=
                    self.public_key.get_fingerprint()):
                raise IncompatibleCiphertextError("The given ciphertext is " \
                        "not decryptable with the selected private key: " \
                        "public key fingerprint mismatch.")

        # We read and decrypt the ciphertext block by block
        # See "Handbook of Applied Cryptography" Algorithm 8.18
        bitstream = BitStream()

        block_size = self.cryptosystem.get_nbits() - 1
        prime = self.cryptosystem.get_prime()
        key = self._key

        # Check if we have a task monitor and register with it
        if (task_monitor != None):
            # One tick per block
            ticks = ciphertext.get_length()
            decrypt_task_mon = \
                task_monitor.new_subtask("Decrypt data", expected_ticks = ticks)

        for gamma, delta in ciphertext:
            assert max(gamma, delta) < 2**(block_size + 1), \
                "The ciphertext object includes blocks larger than the " \
                "expected block size."
            m = (pow(gamma, prime - 1 - key, prime) * delta) % prime
            bitstream.put_num(m, block_size)

            if (task_monitor != None): decrypt_task_mon.tick()

        return bitstream

    def decrypt_to_text(self, ciphertext, task_monitor=None, force=False):
        """
        Decrypts the given ciphertext into its text contents as a string
        
        This method assumes that the ciphertext contains an encrypted stream of 
        data in the format of Note 001 of the Ciphertext.py file, were message 
        contains string information (as opposed to a binary format).
            [size (64 bits) | message (size bits) | padding (X bits) ]
        
        Arguments:
            ciphertext::Ciphertext    -- An encrypted Ciphertext object, 
                                       containing data in the above format.
            task_monitor::TaskMonitor    -- A task monitor for this task.
            force:bool    -- Set to true if you wish to force a decryption 
                           attempt, even when the ciphertext's stored public 
                           key fingerprint does not match that of the public 
                           key associated with this private key.
        
        Returns:
            string::string    -- Decrypted message as a string.
        
        Throws:
            IncompatibleCiphertextError -- The given ciphertext does not appear 
                                           to be decryptable with the selected 
                                           private key.
        """
        bitstream = self.decrypt_to_bitstream(ciphertext, task_monitor, force)
        bitstream.seek(0)
        length = bitstream.get_num(64)
        return bitstream.get_string(length)

    def to_file(self, filename, SerializerClass=serialize.XMLSerializer):
        """
        Saves this private key to a file.
        
        Arguments:
            filename::string    -- The path to the file in which to store the 
                                   serialized PrivateKey object.
            SerializerClass::class --
                The class that provides the serialization. XMLSerializer by 
                default. Must inherit from serialize.BaseSerializer and provide 
                an adequate serialize_to_file method.
                Note that often the same class used to serialize the data must 
                be used to deserialize it.
                (see utilities/serialize.py documentation for more information)
        """
        # Create a new serializer object for the PrivateKey structure definition
        serializer = SerializerClass(PrivateKey_serialize_structure_definition)

        # Helper function to translate large numbers to their hexadecimal
        # string representation
        def num_to_hex_str(num):
            hex_str = hex(num)[2:]  # Remove leading '0x'
            if (hex_str[-1] == 'L'):
                hex_str = hex_str[0:-1]  # Remove trailing 'L'
            return hex_str

        # Generate a serializable data dictionary matching the definition:
        prime_str = num_to_hex_str(self.cryptosystem.get_prime())
        generator_str = num_to_hex_str(self.cryptosystem.get_generator())
        data = {
            "PloneVotePrivateKey": {
                "PrivateKey": num_to_hex_str(self._key),
                "CryptoSystemScheme": {
                    "nbits": str(self.cryptosystem.get_nbits()),
                    "prime": prime_str,
                    "generator": generator_str
                }
            }
        }

        # Use the serializer to store the data to file
        serializer.serialize_to_file(filename, data)

    @classmethod
    def from_file(cls, filename, SerializerClass=serialize.XMLSerializer):
        """
        Loads an instance of PrivateKey from the given file.
        
        Arguments:
            filename::string    -- The name of a file containing the private 
                                   key in serialized form.
            SerializerClass::class --
                The class that provides the deserialization. XMLSerializer by 
                default. Must inherit from serialize.BaseSerializer and provide 
                an adequate deserialize_from_file method.
                Note that often the same class used to serialize the data must 
                be used to deserialize it.
                (see utilities/serialize.py documentation for more information)
        
        Throws:
            InvalidPloneVoteCryptoFileError -- If the file is not a valid 
                                               PloneVoteCryptoLib stored 
                                               private key file.
        """
        # Create a new serializer object for the PrivateKey structure definition
        serializer = SerializerClass(PrivateKey_serialize_structure_definition)

        # Deserialize the PrivateKey instance from file
        try:
            data = serializer.deserialize_from_file(filename)
        except serialize.InvalidSerializeDataError, e:
            # Convert the exception to an InvalidPloneVoteCryptoFileError
            raise InvalidPloneVoteCryptoFileError(filename,
                "File \"%s\" does not contain a valid private key. The " \
                "following error occurred while trying to deserialize the " \
                "file contents: %s" % (filename, str(e)))

        # Helper function to decode numbers from strings and
        # raise an exception if the string is not a valid number.
        # (value_name is used only to construct the exception string).
        def str_to_num(num_str, base, value_name):
            try:
                return int(num_str, base)
            except ValueError:
                raise InvalidPloneVoteCryptoFileError(filename,
                    "File \"%s\" does not contain a valid private key. The " \
                    "stored value for %s is not a valid integer in " \
                    "base %d representation." % (filename, value_name, base))

        # Get the values from the deserialized data
        inner_elems = data["PloneVotePrivateKey"]["CryptoSystemScheme"]
        nbits = str_to_num(inner_elems["nbits"], 10, "nbits")
        prime = str_to_num(inner_elems["prime"], 16, "prime")
        generator = str_to_num(inner_elems["generator"], 16, "generator")

        priv_key = str_to_num(data["PloneVotePrivateKey"]["PrivateKey"], 16,
                              "PrivateKey")

        # Check the loaded values
        if (not (1 <= priv_key <= prime - 2)):
            raise InvalidPloneVoteCryptoFileError(filename,
                "File \"%s\" does not contain a valid private key. The value " \
                "of the private key given in the file does not match the " \
                "indicated cryptosystem. Could the file be corrupt?" % filename)

        # Construct the cryptosystem object
        cryptosystem = EGCryptoSystem.load(nbits, prime, generator)

        # Construct and return the PrivateKey object
        return cls(cryptosystem, priv_key)
Пример #10
0
def run_tool(key_file, in_file, out_file):
    """
	Runs the plonevote.encrypt tool and encrypts in_file into out_file.
	"""
    # Load the public key
    print("Loading public key...")
    try:
        public_key = PublicKey.from_file(key_file)
    except InvalidPloneVoteCryptoFileError as e:
        print("Invalid public key file (%s): %s" % (key_file, e.msg))
        sys.exit(2)

    # Open the input file
    print("Reading input file...")
    try:
        in_f = open(in_file, 'rb')
    except Exception as e:
        print("Problem while opening input file %s: %s" % (in_file, e))

    # Read the whole file into a bitstream
    bitstream = BitStream()
    try:
        read_quantum = 1024  # KB at a time
        bytes = in_f.read(read_quantum)
        while (bytes):
            for byte in bytes:
                bitstream.put_byte(ord(byte))
            bytes = in_f.read(read_quantum)
    except Exception as e:
        print("Problem while reading from input file %s: %s" % (in_file, e))

    in_f.close()

    # Define callbacks for the TaskMonitor for monitoring the encryption process
    if (len(in_file) <= 50):
        short_in_filename = in_file
    else:
        short_in_filename = os.path.split(in_file)[-1]
        if (len(short_in_filename) > 50):
            # Do ellipsis shortening
            short_in_filename = short_in_filename[0,20] + "..." + \
                 short_in_filename[-20,-1]

    def cb_task_percent_progress(task):
        print("  %.2f%% of %s encrypted..." % \
          (task.get_percent_completed(), short_in_filename))

    # Create new TaskMonitor and register the callbacks
    taskmon = TaskMonitor()
    taskmon.add_on_progress_percent_callback(cb_task_percent_progress, \
               percent_span = 5)

    # Encrypt bitstream
    print("Encrypting...")
    ciphertext = public_key.encrypt_bitstream(bitstream, task_monitor=taskmon)

    # Save the ciphertext to the output file
    try:
        ciphertext.to_file(out_file)
    except Exception as e:
        print("Problem while saving the output file %s: %s" % (in_file, e.msg))
Пример #11
0
class PrivateKey:
    """
    An ElGamal private key object used for decryption.
    
    Attributes:
        cryptosystem::EGCryptoSystem    -- The ElGamal cryptosystem in which 
                                           this key is defined.
        public_key::PublicKey    -- The associated public key.
    """
    
    def __eq__(self, other):
        """
        Implements PrivateKey equality.
        """
        if(isinstance(other, PrivateKey) and 
           (other.cryptosystem == self.cryptosystem) and 
           (other.public_key == self.public_key) and  
           (other._key == self._key)):
            return True
        else:
            return False
    
    def __ne__(self, other):
        """
        Implements PrivateKey inequality.
        """
        return not self.__eq__(other)
    
    def __init__(self, cryptosystem, private_key_value):
        """
        Creates a new private key. Should not be invoked directly.
        
        Instead of using this constructor from outside of PloneVoteCryptoLib, 
        please use the class methods EGCryptoSystem.new_key_pair() or 
        PrivateKey.from_file(file).
        
        Arguments:
            cryptosystem::EGCryptoSystem-- The ElGamal cryptosystem in which 
                                           this key is defined.
            private_key_value::long     -- The actual value of the private key.
        """        
        public_key_value = pow(cryptosystem.get_generator(), 
                               private_key_value, 
                               cryptosystem.get_prime())
        
        self.cryptosystem = cryptosystem
        self.public_key = PublicKey(cryptosystem, public_key_value)
        self._key = private_key_value
        
    def decrypt_to_bitstream(self, ciphertext, task_monitor=None, force=False):
        """
        Decrypts the given ciphertext into a bitstream.
        
        If the bitstream was originally encrypted with PublicKey.encrypt_X(), 
        then this method returns a bitstream following the format described 
        in Note 001 of the Ciphertext.py file:
            [size (64 bits) | message (size bits) | padding (X bits) ]
        
        Arguments:
            ciphertext::Ciphertext    -- An encrypted Ciphertext object.
            task_monitor::TaskMonitor    -- A task monitor for this task.
            force:bool    -- Set this to true if you wish to force a decryption 
                           attempt, even when the ciphertext's stored public key
                           fingerprint does not match that of the public key 
                           associated with this private key.
        
        Returns:
            bitstream::Bitstream    -- A bitstream containing the unencrypted 
                                       data.
        
        Throws:
            IncompatibleCiphertextError -- The given ciphertext does not appear 
                                           to be decryptable with the selected 
                                           private key.
        """
        # Check that the public key fingerprint stored in the ciphertext 
        # matches the public key associated with this private key.
        if(not force):
            if(ciphertext.nbits != self.cryptosystem.get_nbits()):
                raise IncompatibleCiphertextError("The given ciphertext is " \
                        "not decryptable with the selected private key: " \
                        "incompatible cryptosystem/key sizes.")
            
            if(ciphertext.pk_fingerprint != self.public_key.get_fingerprint()):
                raise IncompatibleCiphertextError("The given ciphertext is " \
                        "not decryptable with the selected private key: " \
                        "public key fingerprint mismatch.")
        
        # We read and decrypt the ciphertext block by block
        # See "Handbook of Applied Cryptography" Algorithm 8.18
        bitstream = BitStream()
        
        block_size = self.cryptosystem.get_nbits() - 1
        prime = self.cryptosystem.get_prime()
        key = self._key
        
        # Check if we have a task monitor and register with it
        if(task_monitor != None):
            # One tick per block
            ticks = ciphertext.get_length()
            decrypt_task_mon = \
                task_monitor.new_subtask("Decrypt data", expected_ticks = ticks)
        
        for gamma, delta in ciphertext:
            assert max(gamma, delta) < 2**(block_size + 1), \
                "The ciphertext object includes blocks larger than the " \
                "expected block size."
            m = (pow(gamma, prime - 1 - key, prime) * delta) % prime
            bitstream.put_num(m, block_size)
            
            if(task_monitor != None): decrypt_task_mon.tick()
            
        return bitstream
            
    
    def decrypt_to_text(self, ciphertext, task_monitor=None, force=False):
        """
        Decrypts the given ciphertext into its text contents as a string
        
        This method assumes that the ciphertext contains an encrypted stream of 
        data in the format of Note 001 of the Ciphertext.py file, were message 
        contains string information (as opposed to a binary format).
            [size (64 bits) | message (size bits) | padding (X bits) ]
        
        Arguments:
            ciphertext::Ciphertext    -- An encrypted Ciphertext object, 
                                       containing data in the above format.
            task_monitor::TaskMonitor    -- A task monitor for this task.
            force:bool    -- Set to true if you wish to force a decryption 
                           attempt, even when the ciphertext's stored public 
                           key fingerprint does not match that of the public 
                           key associated with this private key.
        
        Returns:
            string::string    -- Decrypted message as a string.
        
        Throws:
            IncompatibleCiphertextError -- The given ciphertext does not appear 
                                           to be decryptable with the selected 
                                           private key.
        """
        bitstream = self.decrypt_to_bitstream(ciphertext, task_monitor, force)
        bitstream.seek(0)
        length = bitstream.get_num(64)
        return bitstream.get_string(length)
    
    def to_file(self, filename, SerializerClass=serialize.XMLSerializer):
        """
        Saves this private key to a file.
        
        Arguments:
            filename::string    -- The path to the file in which to store the 
                                   serialized PrivateKey object.
            SerializerClass::class --
                The class that provides the serialization. XMLSerializer by 
                default. Must inherit from serialize.BaseSerializer and provide 
                an adequate serialize_to_file method.
                Note that often the same class used to serialize the data must 
                be used to deserialize it.
                (see utilities/serialize.py documentation for more information)
        """
        # Create a new serializer object for the PrivateKey structure definition
        serializer = SerializerClass(PrivateKey_serialize_structure_definition)
        
        # Helper function to translate large numbers to their hexadecimal 
        # string representation
        def num_to_hex_str(num):
            hex_str = hex(num)[2:]              # Remove leading '0x'
            if(hex_str[-1] == 'L'): 
                hex_str = hex_str[0:-1]         # Remove trailing 'L'
            return hex_str
        
        # Generate a serializable data dictionary matching the definition:
        prime_str = num_to_hex_str(self.cryptosystem.get_prime())
        generator_str = num_to_hex_str(self.cryptosystem.get_generator())
        data = {
            "PloneVotePrivateKey" : {
                "PrivateKey" : num_to_hex_str(self._key),
                "CryptoSystemScheme" : {
                    "nbits" : str(self.cryptosystem.get_nbits()),
                    "prime" : prime_str,
                    "generator" : generator_str
                }
            }
        }
        
        # Use the serializer to store the data to file
        serializer.serialize_to_file(filename, data)
        
    @classmethod
    def from_file(cls, filename, SerializerClass=serialize.XMLSerializer):
        """
        Loads an instance of PrivateKey from the given file.
        
        Arguments:
            filename::string    -- The name of a file containing the private 
                                   key in serialized form.
            SerializerClass::class --
                The class that provides the deserialization. XMLSerializer by 
                default. Must inherit from serialize.BaseSerializer and provide 
                an adequate deserialize_from_file method.
                Note that often the same class used to serialize the data must 
                be used to deserialize it.
                (see utilities/serialize.py documentation for more information)
        
        Throws:
            InvalidPloneVoteCryptoFileError -- If the file is not a valid 
                                               PloneVoteCryptoLib stored 
                                               private key file.
        """
        # Create a new serializer object for the PrivateKey structure definition
        serializer = SerializerClass(PrivateKey_serialize_structure_definition)
        
        # Deserialize the PrivateKey instance from file
        try:
            data = serializer.deserialize_from_file(filename)
        except serialize.InvalidSerializeDataError, e:
            # Convert the exception to an InvalidPloneVoteCryptoFileError
            raise InvalidPloneVoteCryptoFileError(filename, 
                "File \"%s\" does not contain a valid private key. The " \
                "following error occurred while trying to deserialize the " \
                "file contents: %s" % (filename, str(e)))
                
        # Helper function to decode numbers from strings and 
        # raise an exception if the string is not a valid number.
        # (value_name is used only to construct the exception string).
        def str_to_num(num_str, base, value_name):
            try:
                return int(num_str, base)
            except ValueError:
                raise InvalidPloneVoteCryptoFileError(filename, 
                    "File \"%s\" does not contain a valid private key. The " \
                    "stored value for %s is not a valid integer in " \
                    "base %d representation." % (filename, value_name, base))
                    
        # Get the values from the deserialized data
        inner_elems = data["PloneVotePrivateKey"]["CryptoSystemScheme"]
        nbits = str_to_num(inner_elems["nbits"], 10, "nbits")
        prime = str_to_num(inner_elems["prime"], 16, "prime")
        generator = str_to_num(inner_elems["generator"], 16, "generator")
        
        priv_key = str_to_num(data["PloneVotePrivateKey"]["PrivateKey"], 
                                  16, "PrivateKey")
        
        # Check the loaded values
        if(not (1 <= priv_key <= prime - 2)):
            raise InvalidPloneVoteCryptoFileError(filename, 
                "File \"%s\" does not contain a valid private key. The value " \
                "of the private key given in the file does not match the " \
                "indicated cryptosystem. Could the file be corrupt?" % filename)
        
        # Construct the cryptosystem object
        cryptosystem = EGCryptoSystem.load(nbits, prime, generator)
        
        # Construct and return the PrivateKey object
        return cls(cryptosystem, priv_key)