Beispiel #1
0
        /// <summary>
        /// Encrypts a message
        /// </summary>
        ///
        /// <param name="Input">The message to encrypt</param>
        ///
        /// <returns>The encrypted message</returns>
        ///
        /// <exception cref="NTRUException">If not initialized, the specified hash algorithm is invalid, the encrypted data is invalid, or <c>maxLenBytes</c> is greater than 255</exception>
        public byte[] Encrypt(byte[] Input)
        {
            if (!_isInitialized)
            {
                throw new NTRUException("NTRUEncrypt:Encrypt", "The cipher has not been initialized!", new InvalidOperationException());
            }

            IntegerPolynomial pub = ((NTRUPublicKey)_keyPair.PublicKey).H;
            int  N             = _encParams.N;
            int  q             = _encParams.Q;
            int  maxLenBytes   = _encParams.MaxMsgLenBytes;
            int  db            = _encParams.Db;
            int  bufferLenBits = _encParams.BufferLenBits;
            int  dm0           = _encParams.Dm0;
            int  maxM1         = _encParams.MaxM1;
            int  minCallsMask  = _encParams.MinMGFHashCalls;
            bool hashSeed      = _encParams.HashSeed;
            int  msgLen        = Input.Length;

            //if (maxLenBytes > 255)
            //    throw new NTRUException("len values bigger than 255 are not supported");
            if (msgLen > maxLenBytes)
            {
                throw new NTRUException("NTRUEncrypt:Encrypt", string.Format("Message too long: {0} > {1}!", msgLen, maxLenBytes), new InvalidDataException());
            }

            while (true)
            {
                // M = b|octL|m|p0
                byte[] b = new byte[db / 8];
                // forward padding
                _rndEngine.GetBytes(b);
                byte[] p0 = new byte[maxLenBytes + 1 - msgLen];
                byte[] msgTmp;

                using (BinaryWriter writer = new BinaryWriter(new MemoryStream((bufferLenBits + 7) / 8)))
                {
                    writer.Write(b);
                    writer.Write((byte)msgLen);
                    writer.Write(Input);
                    writer.Write(p0);
                    msgTmp = ((MemoryStream)writer.BaseStream).ToArray();
                }

                // don't use the constant coeff if maxM1 is set; see below
                IntegerPolynomial mTrin = IntegerPolynomial.FromBinary3Sves(msgTmp, N, maxM1 > 0);
                byte[]            sData = GetSeed(Input, pub, b);
                IPolynomial       r     = GenerateBlindingPoly(sData);
                IntegerPolynomial R     = r.Multiply(pub, q);
                byte[]            oR4   = R.ToBinary4();
                IntegerPolynomial mask  = MGF(oR4, N, minCallsMask, hashSeed);
                mTrin.Add(mask);

                // If df and dr are close to N/3, and the absolute value of mTrin.sumCoeffs() is
                // large enough, the message becomes vulnerable to a meet-in-the-middle attack.
                // To prevent this, we set the constant coefficient to zero but first check to ensure
                // sumCoeffs() is small enough to keep the likelihood of a decryption failure low.
                if (maxM1 > 0)
                {
                    if (mTrin.SumCoeffs() > maxM1)
                    {
                        continue;
                    }
                    mTrin.Coeffs[0] = 0;
                }

                mTrin.Mod3();

                if (mTrin.Count(-1) < dm0)
                {
                    continue;
                }
                if (mTrin.Count(0) < dm0)
                {
                    continue;
                }
                if (mTrin.Count(1) < dm0)
                {
                    continue;
                }

                R.Add(mTrin, q);
                R.EnsurePositive(q);

                return(R.ToBinary(q));
            }
        }
Beispiel #2
0
        /// <summary>
        /// Decrypts a message
        /// </summary>
        ///
        /// <param name="Input">The message to decrypt</param>
        ///
        /// <returns>The decrypted message</returns>
        ///
        /// <exception cref="NTRUException">If not initialized, the specified hash algorithm is invalid, the encrypted data is invalid, or <c>MaxLenBytes</c> is greater than 255</exception>
        public byte[] Decrypt(byte[] Input)
        {
            if (!_isInitialized)
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "The cipher has not been initialized!", new InvalidOperationException());
            }

            IPolynomial       priv_t  = ((NTRUPrivateKey)_keyPair.PrivateKey).T;
            IntegerPolynomial priv_fp = ((NTRUPrivateKey)_keyPair.PrivateKey).FP;
            IntegerPolynomial pub     = ((NTRUPublicKey)_keyPair.PublicKey).H;
            int  N               = _encParams.N;
            int  q               = _encParams.Q;
            int  db              = _encParams.Db;
            int  maxMsgLenBytes  = _encParams.MaxMsgLenBytes;
            int  dm0             = _encParams.Dm0;
            int  maxM1           = _encParams.MaxM1;
            int  minCallsMask    = _encParams.MinMGFHashCalls;
            bool hashSeed        = _encParams.HashSeed;
            int  bLen            = db / 8;
            IntegerPolynomial e  = IntegerPolynomial.FromBinary(Input, N, q);
            IntegerPolynomial ci = Decrypt(e, priv_t, priv_fp);

            if (ci.Count(-1) < dm0)
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "Less than dm0 coefficients equal -1", new InvalidDataException());
            }
            if (ci.Count(0) < dm0)
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "Less than dm0 coefficients equal 0", new InvalidDataException());
            }
            if (ci.Count(1) < dm0)
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "Less than dm0 coefficients equal 1", new InvalidDataException());
            }
            //if (maxMsgLenBytes > 255)
            //    throw new NTRUException("NTRUEncrypt:Decrypt", "maxMsgLenBytes values bigger than 255 are not supported", new ArgumentOutOfRangeException());

            IntegerPolynomial cR = e;

            cR.Subtract(ci);
            cR.ModPositive(q);

            byte[]            coR4   = cR.ToBinary4();
            IntegerPolynomial mask   = MGF(coR4, N, minCallsMask, hashSeed);
            IntegerPolynomial cMTrin = ci;

            cMTrin.Subtract(mask);
            cMTrin.Mod3();

            byte[] cb, p0, cm;
            using (BinaryReader reader = new BinaryReader(new MemoryStream(cMTrin.ToBinary3Sves(maxM1 > 0))))
            {
                cb = new byte[bLen];
                reader.Read(cb, 0, cb.Length);
                // llen=1, so read one byte
                int cl = reader.ReadByte() & 0xFF;

                if (cl > maxMsgLenBytes)
                {
                    throw new NTRUException("NTRUEncrypt:Decrypt", string.Format("Message too long: {0} > {1}!", cl, maxMsgLenBytes), new InvalidDataException());
                }

                cm = new byte[cl];
                reader.Read(cm, 0, cm.Length);
                p0 = new byte[reader.BaseStream.Length - reader.BaseStream.Position];
                reader.Read(p0, 0, p0.Length);
            }

            if (!Compare.AreEqual(p0, new byte[p0.Length]))
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "The message is not followed by zeroes!", new InvalidDataException());
            }

            byte[]            sData   = GetSeed(cm, pub, cb);
            IPolynomial       cr      = GenerateBlindingPoly(sData);
            IntegerPolynomial cRPrime = cr.Multiply(pub);

            cRPrime.ModPositive(q);

            if (!cRPrime.Equals(cR))
            {
                throw new NTRUException("NTRUEncrypt:Decrypt", "Invalid message encoding!", new InvalidDataException());
            }

            return(cm);
        }