FileMaker 18 introduces two new cryptographic functions which can be used to generate and verify digital signatures:
Generate digital signature
CryptGenerateSignature ( data ; algorithm ; privateRSAKey ; keyPassword )
Verify digital signature
CryptVerifySignature ( data ; algorithm ; publicRSAKey ; signature )
Why Use Digital Signatures: An Example
Digital signatures are a digital analog to good old-fashioned physical signatures which we’re all familiar with. Digital signatures serve a similar function as physical signatures, but they also provide additional benefits which physical signatures do not. Let’s look at an example.
Back in 2011, I lived in a Chicago condominium building which had six units. In Chicago, the city handles waste removal (trash pickup) for buildings with four units or less, and larger properties are required to contract with a private waste management company. These contracts are frequently structured in a way that causes homeowners to overpay.
Here’s one way how this is done: The contract is set up with a negotiated rate for three years. The customer agrees to the rate and signs the contract. Buried in the fine print is an explanation that the contract will automatically renew at a rate specified by the waste management company (which ends up being much higher than the original rate), and that canceling the automatic renewal must be done within a short time window that ends a month before the original three-year contract expires (probably to increase the chance that this is overlooked by the homeowner).
Our condo association was stuck in one of these automatic renewals for a year, and as that extra contract year came to an end, we shopped around for a better deal. We eventually decided to go with one of the other waste management companies, and I signed a one-year contract with them.
Our current waste removal company found out we were not going to renew, so they called and offered better terms and explained that if we extend our contract with them, it would supersede the new contract which I signed. As part of the back and forth with canceling the new contract, the new company sent me a copy of the contract that I signed, and I noticed a small difference between what they sent me and the copy that I had kept after signing it. They had removed the contract expiration date on their “official” copy of the contract. If we had stayed with them, and if I hadn’t kept a copy of the contract that I signed with them, they could have claimed that I signed a contract for much longer than one year.
My copy of the contract with the end date specified in the “Terms of Agreement” section:
Their “Official” copy of the contract with the end date removed:
The integrity of the contract had been compromised, and this is something that would not have been possible to do if I had signed the contract using a digital signature. If a digitally signed contract is tampered with, the signature is automatically invalidated. Before we look into how that works, let’s review all of the benefits provided with digital signatures.
The Benefits of Using Digital Signatures
Digital signatures can provide these three benefits:
|Benefit||Definition||Physical Signatures||Digital Signatures|
|Authentication||If I sign something, others will know it was signed by me and not someone else, because my signature is uniquely mine and cannot be forged.||Physical signatures afford this protection to a degree, but of course, forgeries are possible.||Digital signatures are created using certificates issued by Certificate Authorities. With a digital signature, I cannot impersonate someone else, because the Certificate Authority will not issue a certificate to me unless I am able to demonstrate that I really am who I say I am.|
|Non-repudiation||If I sign something, I cannot later claim that the signature didn’t come from me.||With a physical signature, I could try to claim that the signature was forged by someone else.||With a digital signature, I cannot claim that I did not sign something while at the same time claiming that my private key is indeed private.|
|Data integrity||If I sign something, I want to feel assured that the contents of what I signed will not change later.||As we saw with my contract example above, physical signatures do not provide this benefit.||If a document is tampered with, the digital signature will not be verified.|
Cryptographic Hash Functions
Before we explain how digital signatures work, let’s do a quick cryptography primer, starting with cryptographic hash functions.
A hash function takes some data (for example, a document) as an input and outputs some other data of fixed size. The input is referred to as the message, and the output is referred to as the digest or hash. Cryptographic hash algorithms have these properties:
- A digest can be computed quickly.
- The original message cannot be derived from the digest.
- Even a small change in the message will result in a completely different digest.
- Digests always have the same length.
- Collisions (where two different messages create the same digest) are hard to create.
For example, the digest of “hello world” (using the SHA-512 hash algorithm) is:
And the digest of the 343-word lyrics of “Stairway To Heaven” is:
Because collisions are unlikely, hash functions that obey the properties listed above can be used to generate a sort of unique identifier. If I use a cryptographically strong hash algorithm, it is essentially impossible for me to come up with a different message that generates the same digest as “hello world.” (We’ll revisit collisions a bit later.)
An encryption algorithm takes some readable text (referred to as cleartext or plaintext) or binary data and converts it into unintelligible data. Decryption is the inverse: convert unreadable, encrypted data into intelligible content.
There are two types of encryption: symmetric and asymmetric.
Symmetric encryption uses the same secret key to both encrypt and decrypt.
Asymmetric encryption uses a public-private key pair. One key is used to encrypt and the other to decrypt. Digital signatures take advantage of this property. The private key is used to generate the signature. This can only be done by someone in possession of the private key, so it’s critical that you keep your private key well secured. The public key is used to verify the signature. The public key can be published far and wide. A copy can be given to whomever asks for it without compromising the security of the signature.
How Digital Signatures Work
Generating the signature:
A cryptographic hash algorithm is used to generate a digest of the message that you would like to have signed. That digest is then encrypted using an asymmetric encryption algorithm and a private key. The encrypted hash serves as the digital signature.
An identifier for the hash algorithm that was used to create the digital signature is embedded in the digital signature itself so that when somebody verifies the signature, they know which hash algorithm to use.
Verifying the signature:
The original message, the digital signature, and a copy of the public key are obtained. The public key is used to decrypt the digital signature, revealing the plaintext digest and the identifier of the hash algorithm that was used to generate the signature. That hash algorithm is then used to generate a new message digest. The two plaintext digests are compared. If they are the same, the digital signature is considered to be verified.
Security Principles Revisited
- Data integrity – If the message is altered in any way (even by just a single bit), the message digest will change too, and the signature will no longer be verifiable. This is what provides data integrity and what was missing in my experience with the waste management company.
- Non-repudiation – If I signed the message, I cannot later claim both (1) that I did not sign it and (2) that my private key is indeed private.
- Authentication – The identity of the owner of the private key is embedded in the certificate that contains the public key. To prevent others from impersonating him, the key owner can have the key signed by a Certificate Authority (CA). As part of this process, the CA will validate the authenticity of the key owner’s identity.
Without the involvement of the Certificate Authority, you would have to take it on faith that the sender of the message is who he says he is. With the Certificate Authority signing the public key, you have to take it on faith that the Certificate Authority did its job properly in terms of validating the authenticity of the key owner.
The job of deciding which Certificate Authorities to trust is generally delegated to the manufacturers of the major web browsers; i.e. Mozilla, Google, Microsoft, Apple, etc. Back in 2005, they established the CA/Browser Forum to ensure that certificate authorities follow best practices (a set of baseline requirements) when they issue certificates.
Generating a Digital Signature Using FileMaker
A digital signature can be generated using this function:
CryptGenerateSignature ( data ; algorithm ; privateRSAKey ; keyPassword )
- data – This parameter is the message that is to be signed. The value can come from a field or a variable and can be text or binary (e.g. container field).
- algorithm – This parameter specifies the cryptographic hash algorithm used to create the digest. Note that we get to choose the hash algorithm (used in step 1 of the signing process), but we don’t get to choose the encryption algorithm (used in step 2). The choice of the encryption algorithm is made for us. FileMaker has settled on using an RSA-based signature scheme, but there are others.
- privateRSAKey – This parameter is the private RSA key that will be used to encrypt the message digest. As a further security precaution, this private key can itself be encrypted with a password. This encryption is done using symmetric encryption (the same password is used to encrypt and decrypt the key) and creates an additional hurdle for a would-be hacker who may have obtained a copy of the private key but still doesn’t know what the encryption password is.
- keyPassword – If the private RSA key is encrypted, then the encryption password is provided in this parameter.
Our choices for the cryptographic hash algorithm are the same as with the CryptAuthCode function:
- MD5 — do not use
- MDC2 — do not use
- SHA1 — do not use
Do not use MD5 or SHA-1, as they have been shown to have security vulnerabilities. MDC-2 may also be unsafe to use based on the information provided in this article.
The CryptGenerateSignature function returns the digital signature as a binary file which can be stored in a container field. As a subsequent step, the digital signature file can also be stored as text using one of the text encoding functions; e.g. Base64Encode.
If any of the parameters are invalid, the function will return “?”.
Note that CryptGenerateSignature does not embed a timestamp inside the signature. This would have been nice to have so that the date and time of when the message was signed could be looked up as part of verifying the signature. One way of adding this to the signature yourself is to include the date and time inside the document that is being signed.
Verifying a Digital Signature Using FileMaker
A digital signature can be verified using this function:
CryptVerifySignature ( data ; algorithm ; publicRSAKey ; signature )
- data – This parameter is the message that was signed and whose signature needs to be verified.
- algorithm – This parameter specifies which cryptographic hash algorithm was used to create the signature. I am not sure why this parameter is needed since the algorithm is also specified inside the signature.
- publicRSAKey – This parameter is the public RSA key that corresponds to the private key that was used in step 2 of the signature generation.
- signature – This parameter is the binary digital signature file. This is the signature that we want to verify.
The function returns 1 if the signature was verified or 0 if it was not. If any of the parameters are invalid, the function will return “?”.
The CryptVerifySignature function will provide data integrity and non-repudiation, but not authenticity. The is because a public key on its own does not include any identifying information about the key owner. To do that, the public key would have to be included in a certificate signed by a Certificate Authority. These certificates are similar to the SSL certificates you may be familiar with. These signing certificates are known as “email and document signing certificates,” and the “common name” in those certificates specifies an email address instead of a domain name. If you are interested in getting one for yourself, you can purchase them at a discount at sites like this one: https://www.gogetssl.com/email-document-signing-certificates/.
If you do end up getting a signing certificate, you can extract the public key from it using this OpenSSL command:
openssl x509 -pubkey -noout -in <certificate_file>
Note: OpenSSL is an open-source cryptography software library. It comes preinstalled on macOS and can be easily installed on Windows.
Here’s a description of the command and the options used with the command:
- x509 — This command instructs OpenSSL to operate on a certificate file.
- -pubkey — This option specifies that the public key should be displayed.
- -noout — This option specifies that the encoded contents of the certificate itself should not be displayed.
- -in — This option specifies the name of the certificate file. (Replace <certificate_file> with your certificate’s file name.)
You can see more details about this OpenSSL command here.
If you would like to experiment with using the new FileMaker functions, take a look at the demo file. I have provided a sample public/private key pair so that you can get started right away.
Collisions with MD5
I mentioned earlier that MD5, MDC-5, and SHA-1 should be avoided. These hash algorithms have known security vulnerabilities and should not be used to generate digital signatures. With MD5 in particular, it is possible to generate versions of the original and tampered documents that share the same MD5 digest in near instant time.
In fact, to demonstrate this, my colleague Brian Engert did just that with the two images of the contract shown above. If you download those two image files and generate an MD5 hash for each one, you’ll notice that they are identical.
You can read more about these vulnerabilities here:
- MD5: https://github.com/corkami/collisions
- SHA-1: https://shattered.io/
- MDC-2: https://www.semanticscholar.org/paper/Cryptanalysis-of-MDC-2-Knudsen-Mendel/adab90fc06c2c14e91b9f7288929cdd2d5b16a52
How to Generate a Public/Private Key Pair
If you want to generate a public/private RSA key pair to use for testing the CryptGenerateSignature and CryptVerifySignature functions, you can do so quickly and easily using the OpenSSL commands shown below. Just don’t forget that a public key by itself does not include any identifying information about the key owner, which means that, while you can achieve data integrity and non-repudiation by using the public key to verify a digital signature, you will not be able to confirm the authenticity of the signature.
Here are the commands to use:
Step 1. Generate an RSA private key:
openssl genrsa -aes256 -out private.pem 4096
- genrsa — This command instructs OpenSSL to generate an RSA key.
- -aes256 — This option specifies that the AES-256 cipher should be used to encrypt the private key.
- -out — This option specifies the name of the private key file that is to be generated.
- 4096 — This is the size of the private key. In this case, we are asking for a 4096-bit key.
You will be prompted to specify an encryption password for the private key when you run this command.
Step 2. Export RSA public key from private key:
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
- rsa — This command instructs OpenSSL to process an RSA key.
- -in — This option specifies the name of the private key file that is to be processed.
- -outform — This option specifies the format of the public key file that is to be exported.
- -pubout — This option instructs the RSA command to output the public key.
- -out — This option specifies the name of the public key file that is to be exported.
You can see more details about these OpenSSL commands here:
- Generate RSA private key: https://www.openssl.org/docs/manmaster/man1/genrsa.html
- Export public key: https://www.openssl.org/docs/manmaster/man1/rsa.html
The CryptGenerateSignature and CryptVerifySignature functions make it possible to create and verify RSA digital signatures for files or text content.
Consider using digital signatures if you have a use case where the transmission of data has to incorporate the data integrity and non-repudiation security principles.
Verifying authenticity may be possible to do as well, although it would require some additional work to set up.
Special thanks to Brian Engert for lending me his expertise in preparing this blog post.