private uint[] sjclDecryptAes()
        {
            int L;
            int ivl = this.sjclBitLength(this.uint32IV) / 8;
            int ol  = this.ctBitLength;

            uint[] outX = this.uint32Out;
            uint[] tag  = this.uint32Tag;
            ol = (ol - this.tagSize) / 8;//out length (byte)
            if (ivl < 7)
            {
                throw new Exception("IV must be at least 7 bytes");
            }
            // compute the length of the length
            uint olx = (uint)ol;

            for (L = 2; L < 4 && (olx >> 8 * L) != 0; L++)
            {
            }
            if (L < 15 - ivl)
            {
                L = 15 - ivl;
            }
            long[] ivx = this.sjclClampForIV(this.uint32IV, 8 * (15 - L));
            // decrypt
            SJCLResult ret = this.sjclCCMCounterMode(outX, ivx, tag, L);

            // check the tag
            uint[] tag2 = this.sjclCCMComputeTag(ret.Data, ivx, L);
            if (this.sjclEqual(ret.Tag, tag2) == false)
            {
                throw new Exception("tag doesn't match");
            }
            return(ret.Data);
        }
        private SJCLResult sjclCCMCounterMode(uint[] aOut, long[] aIV, uint[] aTag, int aL)
        {
            int bl = this.ctBitLength - this.tagSize;//original data size
            int l  = aOut.Length;
            // start the ctr
            long partial = this.sjclPartialLong(8, (uint)(aL - 1), 0);

            long[] partialAr = new long[] { partial }; //one object array
            uint[] temp1     = this.sjclConcat(partialAr, aIV);
            uint[] temp2     = new uint[3];            //{0,0,0}
            uint[] tempMerge = new uint[temp1.Length + temp2.Length];
            Array.Copy(temp1, 0, tempMerge, 0, temp1.Length);
            Array.Copy(temp2, 0, tempMerge, temp1.Length, temp2.Length);//merge
            uint[] ctr = new uint[4];
            Array.Copy(tempMerge, 0, ctr, 0, ctr.Length);
            // en/decrypt the tag
            uint[] cryptCtr = this.sjclCrypt(ctr, false);
            uint[] tag      = this.sjclXOR4(aTag, cryptCtr);
            // en/decrypt the data
            if (l == 0)
            {//data size is 0
                return(new SJCLResult(tag, new uint[0]));
            }
            uint[] enc;
            uint[] aoutx = new uint[aOut.Length + 3];
            Array.Copy(aOut, 0, aoutx, 0, aOut.Length);//extend
            for (int i = 0; i < l; i += 4)
            {
                ctr[3]++;
                enc           = this.sjclCrypt(ctr, false);
                aoutx[i]     ^= enc[0];
                aoutx[i + 1] ^= enc[1];
                aoutx[i + 2] ^= enc[2];
                aoutx[i + 3] ^= enc[3];
            }
            SJCLResult ret = new SJCLResult(tag, this.sjclClamp(aoutx, bl));

            return(ret);
        }