Skip to content

GCM requires padding from client code for no reason #92

Description

@Graveflo

look at the code for GCM encrypt:

proc encrypt*[T](ctx: var GCM[T]; input: openArray[byte]; output: var openArray[byte]) =
  mixin encrypt
  var ectr: array[16, byte]
  assert(len(input) <= len(output))

  var length = len(input)
  var offset = 0
  ctx.datalen += uint64(length)
  while length > 0:
    let uselen = if length < 16: length else: 16
    inc128(ctx.y)
    ctx.cipher.encrypt(ctx.y, ectr)
    for i in 0 ..< uselen:
      output[offset + i] = ectr[i] xor input[offset + i]
    ghash(ctx.buf, ctx.h, output.toOpenArray(offset, offset + uselen - 1))
    length -= uselen
    offset += uselen

here, ectr holds the keystream values that are xored with the input (ectr[i] xor input[offset + i]), but what if the input is not a multiple of 16 bytes? The keystream gets truncated. This means that calling encrypt in multiple chunks does not produce the same output as a full length run when the input chunks are not multiples of 16 bytes. Encrypting and then decrypting will still work the same as long as the chunk sizes are the same (thus the key stream truncates the same way), but kinda sucks. In order for client to code properly use these functions they have to create 16 byte aligned buffers with 0 padding so they can rip the keystream out and manually xor it with the next round of data to keep the stream valid. This requires the entire stream to be copied for no reason.
Fixing this is as simple as lifting ectr into the GCM object and priming it in init. Then just replenish it in encrypt and decrypt when you need more keystream.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions