/// <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); }
/// <summary> /// Treats a sequence of <c>LongInt<<typeparamref name="B"/>></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<<typeparamref name="B"/>></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."); }