module SJCL::Mode::CCM

Constants

NAME

Public Class Methods

computeTag(prf, plaintext, iv, adata, tlen, l) click to toggle source
# File lib/sjcl/ccm.rb, line 57
def self.computeTag(prf, plaintext, iv, adata, tlen, l)
  tlen /= 8
  if (tlen % 2 != 0 || tlen < 4 || tlen > 16)
    raise Error, "ccm: invalid tag length"
  end

  # mac the flags
  mac = [SJCL::BitArray.partial(8, (adata.length > 0 ? 1<<6 : 0) | ((tlen-2) << 2) | l-1)]

  # mac the iv and length
  mac = SJCL::BitArray.concat(mac, iv)
  mac[3] = (mac[3] || 0) | SJCL::BitArray.bitLength(plaintext)/8
  mac = prf.encrypt(mac)
  i=0

  if (adata.length > 0)
    # mac the associated data.  start with its length...
    tmp = SJCL::BitArray.bitLength(adata)/8;
    if (tmp <= 0xFEFF)
      macData = [SJCL::BitArray.partial(16, tmp)];
    elsif (tmp <= 0xFFFFFFFF)
      macData = SJCL::BitArray.concat([SJCL::BitArray.partial(16,0xFFFE)], [tmp]);
    end

    # mac the data itself
    macData = SJCL::BitArray.concat(macData, adata);
    while i < macData.length
      mac = prf.encrypt(SJCL::BitArray.xor4(mac, macData.slice(i,i+4).concat([0,0,0])));
      i+=4
    end
  end

  i = 0
  while i < plaintext.length
    mac = prf.encrypt(SJCL::BitArray.xor4(mac, plaintext.slice(i,i+4).concat([0,0,0])));
    i+=4
  end

  SJCL::BitArray.clamp(mac, tlen * 8)
end
ctrMode(prf, data, iv, tag, tlen, ccml) click to toggle source
# File lib/sjcl/ccm.rb, line 98
def self.ctrMode(prf, data, iv, tag, tlen, ccml)
  l = data.length
  data = data.dup
  bl= SJCL::BitArray.bitLength(data)
  ctr = SJCL::BitArray.concat([SJCL::BitArray.partial(8,ccml-1)],iv).concat([0,0,0]).slice(0,4)
  tag = SJCL::BitArray.xor4(tag,prf.encrypt(ctr))
  tag = SJCL::BitArray.bitSlice(tag, 0, tlen)
  return {tag:tag, data:[]} if (l == 0)
  i = 0
  while i < l
    ctr[3] += 1;
    enc = prf.encrypt(ctr);
    data[i]   = (data[i] || 0) ^ enc[0];
    data[i+1]   = (data[i+1] || 0) ^ enc[1];
    data[i+2]   = (data[i+2] || 0) ^ enc[2];
    data[i+3]   = (data[i+3] || 0) ^ enc[3];
    i += 4
  end
  return { tag: tag, data: SJCL::BitArray.clamp(data,bl) }
end
decrypt(prf, ciphertext, iv, adata=[], tlen=64) click to toggle source
# File lib/sjcl/ccm.rb, line 26
def self.decrypt(prf, ciphertext, iv, adata=[], tlen=64)
  ccml = 2
  ivl = SJCL::BitArray.bitLength(iv) / 8
  ol = SJCL::BitArray.bitLength(ciphertext)
  out = SJCL::BitArray.clamp(ciphertext, ol - tlen)
  tag = SJCL::BitArray.bitSlice(ciphertext, ol - tlen)

  ol = (ol - tlen) / 8;
  raise Error, "ccm: iv must be at least 7 bytes" if (ivl < 7)

  # compute the length of the length
  while ccml < 4 && ((ol & 0xFFFFFFFF) >> 8*ccml > 0)
    ccml += 1
  end

  if (ccml < 15 - ivl)
    ccml = 15-ivl
  end
  iv = SJCL::BitArray.clamp(iv,8*(15-ccml))

  # decrypt
  out = ctrMode(prf, out, iv, tag, tlen, ccml)

  # check the tag
  tag2 = computeTag(prf, out[:data], iv, adata, tlen, ccml)
  if (!SJCL::BitArray.compare(out[:tag], tag2))
    raise TagAuthError, "ccm: tag doesn't match"
  end
  return out[:data]
end
encrypt(prf, plaintext, iv, adata=[], tlen=64) click to toggle source
# File lib/sjcl/ccm.rb, line 8
def self.encrypt(prf, plaintext, iv, adata=[], tlen=64)
  ccml = 2
  out = plaintext.dup
  ivl = SJCL::BitArray.bitLength(iv) / 8
  ol = SJCL::BitArray.bitLength(out) / 8
  raise Error, "ccm: IV must be at least 7 bytes" if ivl < 7
  while ccml < 4 && ((ol & 0xFFFFFFFF) >> 8*ccml > 0)
    ccml += 1
  end
  ccml = 15 - ivl if ccml < 15 - ivl
  iv = SJCL::BitArray.clamp(iv,8*(15-ccml));
  tag = computeTag(prf, plaintext, iv, adata, tlen, ccml)

  # encrypt
  out = ctrMode(prf, out, iv, tag, tlen, ccml)
  SJCL::BitArray.concat(out[:data], out[:tag])
end