GCM-encrypted data has an authentication tag that serves as an integrity protection mechanism. It is essentially a keyed hash of the ciphertext. If the ciphertext is broken, for example because someone tampered with it or because an encrypted file is corrupted due to hardware issues, the authentication tag no longer matches the ciphertext and becomes invalid.
Some libraries will refuse to decrypt the ciphertext if the authentication tag is invalid. This is probably a good decision: The whole point of authenticated encryption is to make it impossible to tamper with encrypted data. And it probably prevents security issues and makes developers' lives a little easier, since they don't have to decide whether to authenticate ciphertext. If they use authenticated encryption, the authentication tag must be valid. Period.
However, if you still want to decrypt the ciphertext, you can choose a GCM implementation that doesn't enforce authentication. OpenSSL is such a library, as you can see from this example. But there is another option that I find interesting because it reveals something about the inner workings of GCM: You can use CTR mode for decryption. This is what I'm going to describe here.
Counter Mode
I've written about Counter Mode (CTR) in a previous post. Its specification doesn't really prescribe a way of generating counter blocks. So you start with any sequence of distinct blocks (called counter blocks). You encrypt them and then XOR the result with your plaintext (to encrypt) or your ciphertext (to decrypt). That's basically it.
Although the CTR spec doesn't prescribe a way of generating counter blocks, it recommends the so-called standard incrementing function in Appendix B. The idea is this: You start with any block, usually 128 bits, and you choose how many bits to use as the counter. Say, 32 bits. Now, the standard incrementing function interprets the 32 least-significant bits of the block as an integer and increments it. This can be done again and again until all 32 counter bits are 1. Then the counter "wraps", so in the next block all counter bits will be 0. For example, if the counter length is indeed 32 bits (4 bytes), then a sequence of counter blocks in hexadecimal representation might look like this (starting with a random block):
63a962e5207b6f0174bfb64ee2d1bcee
63a962e5207b6f0174bfb64ee2d1bcef
63a962e5207b6f0174bfb64ee2d1bcf0
63a962e5207b6f0174bfb64ee2d1bcf1
- ...
63a962e5207b6f0174bfb64efffffffe
63a962e5207b6f0174bfb64effffffff
63a962e5207b6f0174bfb64e00000000
63a962e5207b6f0174bfb64e00000001
You can use CTR in a spec-compliant way and generate your counter blocks differently. But this is the algorithm recommended in the spec.
Galois/Counter Mode
Galois/Counter Mode (GCM) doesn't just add the authentication tag to CTR. It is also more specific in three aspects—so you could say, GCM is an extension (adding the authentication tag) of a special case of CTR (being more specific about certain things).
The GCM spec is more specific than the CTR spec in the following ways:
- Block size: For CTR, you can choose any block size. For GCM, the block size must be 128 bits.
- The incrementing function: GCM makes the standard incrementing function mandatory. GCM also restricts the counter length: It must be 32 bits.
- The initial counter block: For CTR, you can choose any initial counter block, while GCM has a built-in way of generating the first counter block. GCM needs an initialization vector (IV) as input, and the algorithm for generating the first counter block depends on the length of the IV. Usually, you have a 96-bit IV, and in this case the first counter block is
IV || 00000002
(the counter part again in hexadecimal representation).
Decrypt GCM ciphertext with CTR
After this little comparison, we can easily decrypt GCM ciphertext with CTR—at least as long as our IV for GCM has a length of 96 bits; the case for other IV lengths is a bit more complicated and I will ignore it for now. For CTR decryption, we simply have to choose the standard incrementing function with a counter length of 32 bits and IV || 00000002
as the initial counter block.
We can test this idea using the Web Crypto API. It implements CTR and GCM and, luckily, uses the standard incrementing function for CTR. So we only have to choose the right counter length and initial counter block.
I have written a little web tool, which you can use to play around with this idea. Note that the Crypto API adds the GCM authentication tag to the ciphertext. By default, the authentication tag has a length of 128 bits. So when you encrypt something with GCM in the browser and decrypt the result with CTR, you'll get your original plaintext plus 128 bits of garbage, which are the result of "decrypting" the authentication tag.
Top comments (0)