示例#1
0
        /// <summary>
        /// Encrypts a long integer number using the RSA algorithm.
        /// In case when the number to encrypt is bigger than the public key,
        /// its copy is continously divided by the key until it becomes zero, and remainders are encrypted.
        /// </summary>
        /// <typeparam name="B">An implementation of <see cref="IBase"/> interface which specifies the digit base of the encrypted number.</typeparam>
        /// <typeparam name="E">An implementation of <see cref="IBase"/> interface which specifies the digit base of the public exponent. Should be a power of 2 for faster encryption.</typeparam>
        /// <param name="number">The number to encrypt.</param>
        /// <param name="publicKey">The public key of the RSA algorithm. Should be a product of two big prime numbers.</param>
        /// <param name="publicExponent">The public exponent of the RSA algorithm. Should be relatively prime to Euler's totient function value for <paramref name="publicKey"/>.</param>
        /// <param name="bnem"> Option specifying how numbers bigger than the <paramref name="publicKey"/> are handled when encrypted using the RSA algorithm.</param>
        /// <remarks>If <paramref name="publicExponent"/> has digit base which is a power of 2, the decryption process will go faster.</remarks>
        /// <returns>A sequence of encrypted values, which, along with <paramref name="bnem"/> parameter, allows decryption using <c>Decrypt()</c> method.</returns>
        public static List <LongInt <B> > Encrypt <B, E>(LongInt <B> number, LongInt <B> publicKey, LongInt <E> publicExponent, BigNumberEncryptionMethod bnem)
            where B : IBase, new()
            where E : IBase, new()
        {
            Contract.Requires <ArgumentNullException>(number != null, "number");
            Contract.Requires <ArgumentNullException>(publicKey != null, "publicKey");

            Contract.Requires <ArgumentException>(number > 0, "The encrypted number should not be negative.");
            Contract.Requires <ArgumentException>(publicExponent > 0, "The public exponent should not be zero.");
            Contract.Requires <ArgumentException>(publicKey.Length > 1 || bnem != BigNumberEncryptionMethod.Splitting, "When using the 'splitting' big number encryption option, the number of digits in the public key should be more than 1.");

            List <LongInt <B> > result = new List <LongInt <B> >();

            // Если число меньше ключа, можно его со спокойной душой кодировать
            // и пихать в массив.

            if (number < publicKey)
            {
                result.Add(LongInt <B> .Helper.PowerIntegerModular(number, publicExponent, publicKey));
                return(result);
            }
            else if (bnem == BigNumberEncryptionMethod.Division)
            {
                while (number > publicKey)
                {
                    // Пока число больше открытого ключа, надо брать остатки от деления и
                    // кодировать их.

                    LongInt <B> remainder;

                    number = LongInt <B> .Helper.Div(number, publicKey, out remainder);

                    remainder = LongInt <B> .Helper.PowerIntegerModular(remainder, publicExponent, publicKey);

                    result.Add(remainder);
                }

                result.Add(LongInt <B> .Helper.PowerIntegerModular(number, publicExponent, publicKey));
            }
            else if (bnem == BigNumberEncryptionMethod.Splitting)
            {
                // Разбиваем цифры исходного числа на сегменты длиной N-1, где N - длина открытого ключа.
                // Кодируем эти числа.

                List <ListSegment <int> > numberSegments = number.Digits.CoverWithSegments(publicKey.Length - 1, ListSegmentationExtensions.SegmentationOptions.SmallerLastSegment);

                foreach (ListSegment <int> ls in numberSegments)
                {
                    LongInt <B> currentEncodedNumber = new LongInt <B>(LongInt <B> .BASE, ls, false);
                    currentEncodedNumber = LongInt <B> .Helper.PowerIntegerModular(currentEncodedNumber, publicExponent, publicKey);

                    result.Add(currentEncodedNumber);
                }
            }
            else
            {
                throw new EnumFattenedException("Big number encryption method enum has been fattened, encryption process stuck.");
            }

            return(result);
        }
示例#2
0
        /// <summary>
        /// Treats a sequence of <c>LongInt&lt;<typeparamref name="B"/>&gt;</c> numbers as
        /// a single big number which has been encrypted modulo <paramref name="publicKey"/> and
        /// returns the result of decryption.
        /// </summary>
        /// <typeparam name="B">An implementation of <c>IBase</c> interface which specifies the digit base of <c>LongInt&lt;<typeparamref name="B"/>&gt;</c> numbers.</typeparam>
        /// <typeparam name="E">An implementation of <see cref="IBase"/> interface which specifies the digit base of the public exponent. Should be a power of 2 for faster encryption.</typeparam>
        /// <param name="numberSequence">A sequence of encrypted numbers which are treated as a single number which was bigger than the <paramref name="publicKey"/> during the encryption process.</param>
        /// <param name="publicKey">The public key which was used during the encryption process. Should be a product of two primes.</param>
        /// <param name="secretExponent">The secret exponent of the RSA algorithm.</param>
        /// <param name="bnem">Options which were used during the encryption process. Wrong options will result in a wrong decryption.</param>
        /// <remarks>If <paramref name="secretExponent"/> has digit base which is a power of 2, the decryption process will go faster.</remarks>
        /// <returns>With all conditions of the RSA met and correct options specified, the method returns the decrypted number.</returns>
        public static LongInt <B> DecryptAsSingle <B, E>(IEnumerable <LongInt <B> > numberSequence, LongInt <B> publicKey, LongInt <E> secretExponent, BigNumberEncryptionMethod bnem)
            where B : IBase, new()
            where E : IBase, new()
        {
            Contract.Requires <ArgumentNullException>(numberSequence != null, "numberSequence");
            Contract.Requires <ArgumentException>(numberSequence.Count() > 0, "The sequence should contain at least one encrypted number.");
            Contract.Requires <ArgumentException>(secretExponent > 0, "The secret exponent should be positive.");

            Contract.Requires(Contract.ForAll(numberSequence, x => x != null), "At least one number in the sequence is null.");
            Contract.Requires(Contract.ForAll(numberSequence, x => !x.Negative), "At least one number in the sequence is negative.");

            int count = numberSequence.Count();

            if (count == 1)
            {
                return(Decrypt(numberSequence.Single(), publicKey, secretExponent));
            }

            List <LongInt <B> > list = new List <LongInt <B> >(count);

            foreach (LongInt <B> encryptedNumber in numberSequence)
            {
                list.Add(Decrypt(encryptedNumber, publicKey, secretExponent));
            }

            if (bnem == BigNumberEncryptionMethod.Splitting)
            {
                return(new LongInt <B>(LongInt <B> .BASE, list.SelectMany(x => x.Digits).ToList(), false));
            }

            else if (bnem == BigNumberEncryptionMethod.Division)
            {
                LongInt <B> result = list[list.Count - 1];

                for (int i = list.Count - 2; i >= 0; --i)
                {
                    result = result * publicKey + list[i];
                }

                return(result);
            }

            throw new EnumFattenedException("Big number encryption method enum has been fattened, decryption process stuck.");
        }