internal override bool Decrypt(int recordType, int version, byte[] data, ref int off, ref int len) { int blen = bc.BlockSize; int hlen = hm.MACSize; /* * Grab a copy of the last encrypted block; this is * the "saved IV" for the next record. */ Array.Copy(data, off + len - blen, ivTmp, 0, blen); /* * Decrypt the data. The length has already been * checked. If there is an explicit IV, it gets * "decrypted" as well, which is not a problem. */ bc.CBCDecrypt(iv, data, off, len); Array.Copy(ivTmp, 0, iv, 0, blen); if (explicitIV) { off += blen; len -= blen; } /* * Compute minimum and maximum length of plaintext + MAC. * These can be inferred from the observable record length, * and thus are not secret. */ int minLen = (hlen + 256 < len) ? len - 256 : hlen; int maxLen = len - 1; /* * Get the actual padding length and check padding. The * padding length must match the minLen/maxLen range. */ int padLen = data[off + len - 1]; int good = ~(((maxLen - minLen) - padLen) >> 31); int lenWithMAC = minLen ^ (good & (minLen ^ (maxLen - padLen))); int dbb = 0; for (int i = minLen; i < maxLen; i++) { dbb |= ~((i - lenWithMAC) >> 31) & (data[off + i] ^ padLen); } good &= ~((dbb | -dbb) >> 31); /* * Extract the MAC value; this is done in one pass, but * results in a "rotate" MAC value. The rotation count * is kept in 'rotCount': this is the offset of the * first MAC value byte in tmp1[]. */ int lenNoMAC = lenWithMAC - hlen; minLen -= hlen; int rotCount = 0; for (int i = 0; i < hlen; i++) { tmp1[i] = 0; } int v = 0; for (int i = minLen; i < maxLen; i++) { int m = ~((i - lenNoMAC) >> 31) & ((i - lenWithMAC) >> 31); tmp1[v] |= (byte)(m & data[off + i]); m = i - lenNoMAC; rotCount |= ~((m | -m) >> 31) & v; if (++v == hlen) { v = 0; } } maxLen -= hlen; /* * Rotate back the MAC value. We do it bit by bit, with * 6 iterations; this is good for all MAC value up to * and including 64 bytes. */ for (int i = 5; i >= 0; i--) { int rc = 1 << i; if (rc >= hlen) { continue; } int ctl = -((rotCount >> i) & 1); for (int j = 0, k = rc; j < hlen; j++) { int b1 = tmp1[j]; int b2 = tmp1[k]; tmp2[j] = (byte)(b1 ^ (ctl & (b1 ^ b2))); if (++k == hlen) { k = 0; } } Array.Copy(tmp2, 0, tmp1, 0, hlen); rotCount &= ~rc; } /* * Recompute the HMAC value. At that point, minLen and * maxLen have been adjusted to match the plaintext * without the MAC. */ IO.Enc64be(seq++, tmp2, 0); IO.WriteHeader(recordType, version, lenNoMAC, tmp2, 8); hm.Update(tmp2, 0, 13); hm.ComputeCT(data, off, lenNoMAC, minLen, maxLen, tmp2, 0); /* * Compare MAC values. */ dbb = 0; for (int i = 0; i < hlen; i++) { dbb |= tmp1[i] ^ tmp2[i]; } good &= ~((dbb | -dbb) >> 31); /* * We must also check that the plaintext length fits in * the maximum allowed by the standard (previous check * was on the encrypted length). */ good &= (lenNoMAC - 16385) >> 31; len = lenNoMAC; return(good != 0); }