Practical digital business contracts

When entering into a contract with a customer, it is no longer necessary (at least in Finland) to physically transmit signed copies of a paper copy.

While convenient, given how easy digital images are to counterfeit, this raises a question of how to make sure the digital copy is not later modified by either party of an agreement. It would be easy to for example a buyer to replace the price of the contract with a lower figure by a simple Photoshop operation.

Of course, a prudent organization keeps copies of all digital contracts. So any changes made later can be detected by comparing the copies. However such checks can be time-consuming; a large contract can be dozens of pages. On first thought, checking that the file sizes match sounds like a good idea, too. However it’s also easy to add (or remove) some data from a file transparently so that file sizes match.

So, how to reliably compare an original and a copy that’s been received afterwards? There is a solution: one can generate a so-called cryptographic hash string that serves as a fingerprint of the original file. The way these hashes are generated ensures that any changes to the file will result in a different hash. So one can later easily check that the copy is a faithful copy of the original, by checking whether their hashes match.

A even better solution is to use digital signatures enabled by public key cryptography: First, a key pair is created, consisting of a private key that’s kept secret, and a public key that can be distributed or published freely. The two keys are created from a common “origin” in a way that makes it possible to use them together in a very smart way.

What happens when digital signatures are created  is that the secret private key is used to “stamp” the hash. The public key can then be used to later verify that the stamp was indeed created using the private key – in other words, by the party that gave us the digital signature.

So as a result, by using digital signatures, we can make sure that the contract copies both parties possess are the same, and also that the copy was sent to us by the contractual other party.

Here’s a simple Python module providing a command-line utility to create and verify digital keys and signatures.

"""digicheck - create and verify signatures for files
digicheck keys
digicheck public <keyfilename>
digicheck sign <filename> <keyfilename>
digicheck check <filename> <keyfilename> <signaturefilename>
digicheck (-h | --help)
digicheck --version
Use the command-line to first create a key pair, then a
signature for a file, and finally when you need to make
sure file has not been tampered with in the meantime,
check that the signatures are still equal.
-h --help Show this screen.
--version Show version.
import sys
import docopt
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto import Random
def generate_keys():
random_generator =
key = RSA.generate(2048, random_generator)
return (key.exportKey(), key.publickey().exportKey())
def generate_hash(data):
def generate_signature(hash, key):
return key.sign(hash, '')
def verify_signature(hash, public_key, signature):
return public_key.verify(hash, signature)
if __name__ == "__main__":
args = docopt.docopt(__doc__)
if args["keys"]:
private, public = generate_keys()
keys = private + "\n\n" + public
elif args["public"]:
with open(args["<keyfilename>"], "r") as keyfile:
public_key ="\n\n")[1]
elif args["sign"]:
with open(args["<filename>"], "rb") as signedfile:
hash = generate_hash(
with open(args["<keyfilename>"], "r") as keyfile:
private_key = RSA.importKey("\n\n")[0].strip())
print(generate_signature(hash, private_key)[0])
elif args["check"]:
with open(args["<filename>"], "rb") as signedfile:
hash = generate_hash(
with open(args["<keyfilename>"], "r") as keyfile:
public_key = RSA.importKey("\n\n")[1].strip())
with open(args["<signaturefilename>"], "r") as signaturefile:
signature = long(
if verify_signature(hash, public_key, (signature,)):
sys.exit("valid signature :)")
sys.exit("invalid signature! :(")
view raw hosted with ❤ by GitHub

For more details, see for example the blog post by Laurent Luce, describing the use of PyCrypto.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s