예제 #1
0
        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);
        }