Пример #1
0
        private void OnPrimeGenerated(Object sender, RunWorkerCompletedEventArgs e)
        {
            m_primeProgress += 50;

            if (m_primeProgress == 100)
            {
                //Verify that P and Q are not equal...if they are, we need to regenerate Q
                //Handle the case where Q and P might end up being equal.  This will run 
                //the worker again using the same settings as before.
                BigInteger biP = new BigInteger(m_RSAParams.P);
                BigInteger biQ = new BigInteger(m_RSAParams.Q);

                if (biP == biQ)
                {
                    m_primeProgress = 50;
                    m_worker2.DoWork += Generate_Q;
                    m_worker2.RunWorkerAsync();
                    return;
                }

                if (biP < biQ)
                {
                    BigInteger biTmp = new BigInteger(biP);
                    biP = biQ;
                    biQ = biTmp;
                    m_RSAParams.P = biP.getBytesRaw();
                    m_RSAParams.Q = biQ.getBytesRaw();
                }

                BuildKeys();
            }


        }
Пример #2
0
        /// <summary>
        /// Generate the RSA Key Pair using a supplied cipher strength value and exponent value.  
        /// A prime number value between 3 and 65537 is recommended for the exponent.  Larger 
        /// exponents can increase security but also increase encryption time.  Your supplied 
        /// exponent may be automatically adjusted to ensure compatibility with the RSA algorithm 
        /// security requirements.  If a cipherStrength was specified in the constructor, 
        /// the supplied <paramref name="cipherStrength"/> value will override it.
        /// </summary>
        /// <param name="cipherStrength">The strength of the cipher in bits.  Must be a multiple of 8 
        /// and between 256 and 4096</param>
        /// <param name="exponent">Custom exponent value to be used for RSA Calculation</param>
        public void GenerateKeys(int cipherStrength, int exponent)
        {
            if ((cipherStrength > 4096) || (cipherStrength < 256) || (cipherStrength % 8 != 0))
                throw new ArgumentException("cipherStrength must be a value between 256 and 4096 and must be a multiple of 8.");

            if (m_isBusy == true)
                throw new CryptographicException("Operation cannot be performed while a current key generation operation is in progress.");

            m_KeyLoaded = false;
            m_isBusy = true;

            //bitLength is used to calculate P and Q, so it needs
            //to be half of the cipherStrength.  bitLength 512 = 1024-bit encryption.
            m_bitLength = cipherStrength / 2;

            //Make sure this is a positive number
            BigInteger iExp = new BigInteger(Math.Abs((long)exponent));

            //Make sure this is an odd number
            if (iExp % 2 == 0)
            {
                iExp += 1;
            }

            m_RSAParams.E = iExp.getBytesRaw();

            m_primeProgress = 0;
            m_worker1 = new BackgroundWorker();
            m_worker2 = new BackgroundWorker();
            m_worker1.RunWorkerCompleted += OnPrimeGenerated;
            m_worker2.RunWorkerCompleted += OnPrimeGenerated;

            Generate_Primes();
        }
Пример #3
0
        private void BuildKeys()
        {
            //Make a call to Generate_Primes.
            BigInteger P = new BigInteger(m_RSAParams.P);
            BigInteger Q = new BigInteger(m_RSAParams.Q);

            //Exponent.  This needs to be a number such that the 
            //GCD of the Exponent and Phi is 1.  The larger the exp. 
            //the more secure, but it increases encryption time.
            BigInteger E = new BigInteger(m_RSAParams.E);

            BigInteger N = new BigInteger(0);
            //Public and Private Key Part (Modulus)
            BigInteger D = new BigInteger(0);
            //Private Key Part
            BigInteger DP = new BigInteger(0);
            BigInteger DQ = new BigInteger(0);
            BigInteger IQ = new BigInteger(0);
            BigInteger Phi = new BigInteger(0);
            //Phi

            //Make sure P is greater than Q, swap if less.
            if (P < Q)
            {
                BigInteger biTmp = P;
                P = Q;
                Q = biTmp;
                biTmp = null;

                m_RSAParams.P = P.getBytesRaw();
                m_RSAParams.Q = Q.getBytesRaw();
            }

            //Calculate the modulus
            N = P * Q;
            m_RSAParams.N = N.getBytesRaw();

            //Calculate Phi
            Phi = (P - 1) * (Q - 1);
            m_RSAParams.Phi = Phi.getBytesRaw();


            //Make sure our Exponent will work, or choose a larger one.
            while (Phi.gcd(E) > 1)
            {
                //If the GCD is greater than 1 iterate the Exponent
                E = E + 2;
                //Also make sure the Exponent is prime.
                while (!E.isProbablePrime())
                {
                    E = E + 2;
                }
            }

            //Make sure the params contain the updated E value
            m_RSAParams.E = E.getBytesRaw();


            //Calculate the private exponent D.
            D = E.modInverse(Phi);
            m_RSAParams.D = D.getBytesRaw();

            //Calculate DP
            DP = E.modInverse(P - 1);
            m_RSAParams.DP = DP.getBytesRaw();

            //Calculate DQ
            DQ = E.modInverse(Q - 1);
            m_RSAParams.DQ = DQ.getBytesRaw();

            //Calculate InverseQ
            IQ = Q.modInverse(P);
            m_RSAParams.IQ = IQ.getBytesRaw();

            m_KeyLoaded = true;
            m_isBusy = false;

            OnKeysGenerated(this);

        }
Пример #4
0
        /// <summary>
        /// Adds padding to the input data and returns the padded data.
        /// </summary>
        /// <param name="dataBytes">Data to be padded prior to encryption</param>
        /// <param name="params">RSA Parameters used for padding computation</param>
        /// <returns>Padded message</returns>
        public byte[] EncodeMessage(byte[] dataBytes, RSAParameters @params)
        {
            //Iterator
            int i = 0;

            //Get the size of the data to be encrypted
            m_mLen = dataBytes.Length;

            //Get the size of the public modulus (will serve as max length for cipher text)
            m_k = @params.N.Length;

            if (m_mLen > GetMaxMessageLength(@params))
            {
                throw new CryptographicException("Bad Data.");
            }

            //Generate the random octet seed (same length as hash)
            BigInteger biSeed = new BigInteger();
            biSeed.genRandomBits(m_hLen * 8, new Random());
            byte[] bytSeed = biSeed.getBytesRaw();

            //Make sure all of the bytes are greater than 0.
            for (i = 0; i <= bytSeed.Length - 1; i++)
            {
                if (bytSeed[i] == 0x00)
                {
                    //Replacing with the prime byte 17, no real reason...just picked at random.
                    bytSeed[i] = 0x17;
                }
            }

            //Mask the seed with MFG Function(SHA1 Hash)
            //This is the mask to be XOR'd with the DataBlock below.
            byte[] dbMask = Mathematics.OAEPMGF(bytSeed, m_k - m_hLen - 1, m_hLen, m_hashProvider);

            //Compute the length needed for PS (zero padding) and 
            //fill a byte array to the computed length
            int psLen = GetMaxMessageLength(@params) - m_mLen;

            //Generate the SHA1 hash of an empty L (Label).  Label is not used for this 
            //application of padding in the RSA specification.
            byte[] lHash = m_hashProvider.ComputeHash(System.Text.Encoding.UTF8.GetBytes(string.Empty.ToCharArray()));

            //Create a dataBlock which will later be masked.  The 
            //data block includes the concatenated hash(L), PS, 
            //a 0x01 byte, and the message.
            int dbLen = m_hLen + psLen + 1 + m_mLen;
            byte[] dataBlock = new byte[dbLen];

            int cPos = 0;
            //Current position

            //Add the L Hash to the data blcok
            for (i = 0; i <= lHash.Length - 1; i++)
            {
                dataBlock[cPos] = lHash[i];
                cPos += 1;
            }

            //Add the zero padding
            for (i = 0; i <= psLen - 1; i++)
            {
                dataBlock[cPos] = 0x00;
                cPos += 1;
            }

            //Add the 0x01 byte
            dataBlock[cPos] = 0x01;
            cPos += 1;

            //Add the message
            for (i = 0; i <= dataBytes.Length - 1; i++)
            {
                dataBlock[cPos] = dataBytes[i];
                cPos += 1;
            }

            //Create the masked data block.
            byte[] maskedDB = Mathematics.BitwiseXOR(dbMask, dataBlock);

            //Create the seed mask
            byte[] seedMask = Mathematics.OAEPMGF(maskedDB, m_hLen, m_hLen, m_hashProvider);

            //Create the masked seed
            byte[] maskedSeed = Mathematics.BitwiseXOR(bytSeed, seedMask);

            //Create the resulting cipher - starting with a 0 byte.
            byte[] result = new byte[@params.N.Length];
            result[0] = 0x00;

            //Add the masked seed
            maskedSeed.CopyTo(result, 1);

            //Add the masked data block
            maskedDB.CopyTo(result, maskedSeed.Length + 1);

            return result;
        }