前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C#笔记:RSA加解密实现

C#笔记:RSA加解密实现

作者头像
超级大猪
发布2019-11-22 09:47:11
1.5K0
发布2019-11-22 09:47:11
举报
文章被收录于专栏:大猪的笔记

上回研究产生大素数,产生大素数,肯定是和加密有关的。现在我们就来实现RSA算法。哈哈。

第一步,随机选择两个不相等的质数p和q。

第二步,计算p和q的乘积n。

第三步,计算n的欧拉函数φ(n)。 

根据公式:φ(n) = (p-1)(q-1) 

第四步,随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。一般取e1=65537 第五步,计算e对于φ(n)的模反元素d。  满足e*d ≡ 1 (mod φ(n))即可。 原理讲完了。现在贴代码:

代码语言:javascript
复制
BigInteger p = GetPrimeNum.CreatePrimeNum(128);
            Console.WriteLine("p:" + p);
            Console.WriteLine();
            BigInteger q = GetPrimeNum.CreatePrimeNum(128);
            Console.WriteLine("q:" + q);
            Console.WriteLine();
            BigInteger on = (p - 1) * (q - 1);
            Console.WriteLine("o(n):" + on);
            Console.WriteLine();
            BigInteger n = p * q;
            Console.WriteLine("n:" + n);
            Console.WriteLine();
            BigInteger e1 = BigInteger.Parse("65537");
            Console.WriteLine("e1:" + e1);
            Console.WriteLine();
            BigInteger d = RSAProvider.CreateD(e1, on);
            Console.WriteLine("d:" + d);
            Console.WriteLine();
            Console.WriteLine("加密123");
            BigInteger c = RSAProvider.RsaEncrypt(123, e1, n);
            Console.WriteLine("c:" + c);
            Console.WriteLine("解密C");
            BigInteger m = RSAProvider.RsaEncrypt(c, d, n);
            Console.WriteLine("m:" + m);
 
 
 
 public static class RSAProvider
    {
        /*
          int r = MaxDivisorex(1769, 551, out a, out b);
            MessageBox .Show(string.Format ("{0} * 1769 + {1} *551 = {2}",a,b,(a*1769+b*551)));
         * 扩展欧几里德算法
         * 
         */
        private static BigInteger ext_euclid(BigInteger a, BigInteger b, out BigInteger x, out BigInteger y)
        {
            BigInteger t, d;
            if (b == 0) { x = 1; y = 0; return a; }
            d = ext_euclid(b, a % b, out x, out y);
            t = x;
            x = y;
            y = t - a / b * y;
            return d;
        }
        public static BigInteger CreateD(BigInteger e1, BigInteger on)
        {
            BigInteger d;
            BigInteger y;
            RSAProvider.ext_euclid(e1, on, out d, out y);
            if (d.Sign == -1)
            {
                int i = 1;
                while (true)
                {
                    if (((1 + i * on) % e1) == 0)
                    {
                        d = (1 + i * on) / e1;
                        y = i * (-1);
                        break;
                    }
                    ++i;
                }
            }
            return d;
        }
        public static BigInteger RsaEncrypt(BigInteger m, BigInteger e1, BigInteger n)
        {
            BigInteger c = BigInteger.ModPow(m, e1, n);
            return c;
        }
        public static BigInteger RsaDecrypt(BigInteger c, BigInteger d, BigInteger n)
        {
            return BigInteger.ModPow(c, d, n);
        }
    }
    
    public static class GetPrimeNum
    {
        static RandomNumberGenerator rng = RandomNumberGenerator.Create();
        public static BigInteger CreateRandomNum(int length)
        {
            byte[] bytes = new byte[length];
            rng.GetBytes(bytes);
            BigInteger a = new BigInteger(bytes);
            if (a.IsEven)//如果是偶数就加一
            {
                a += 1;
            }
            if (a.Sign == -1)//如果是负数就乘-1
            {
                a *= -1;
            }
            return a;
        }
        static ManualResetEvent mre = new ManualResetEvent(false);//线程阻塞器设置为阻塞状态
        static BigInteger result = BigInteger.Zero;//result的初始化值设为0
        //候选数的工作队列,线程从此队列取数验证直到找到素数
        static BlockQueue<BigInteger> quePrime = new BlockQueue<BigInteger>(2000);
        
        //这个标签用来在运算完毕后结束多余的线程
        private static volatile bool isOver = false;
        public static BigInteger CreatePrimeNum(int length)
        {
            //将线程阻塞器设置为阻塞状态。此状态下,主线程会等待工作线程找到数再返回result。
            mre.Reset();
            isOver = false;
            //初始化7个任务用来对队列中的数进行取数验证
            //使用的是系统默认的线程池,当线程池中有空余线程时,会对这7个任务进行计算。
            for (int i = 0; i < 7; i++)
            {
                ThreadPool.QueueUserWorkItem(ThreadMethod, mre);
            }
            //每次工作时将队列清除
            quePrime.Clear();
            //重新初始化种子值,一个1024bit的数。
            BigInteger bigNum = CreateRandomNum(128);
            //将种子值也入队
            quePrime.EnQueue(bigNum);
            //这个线程不断的把种子值+2入队,以免队列空虚使得死锁。
            Thread thInsertNum = new Thread(new ThreadStart(delegate
            {
                while (true)
                {
                    bigNum += 2;
                    quePrime.EnQueue(bigNum);
                }
            }));
            thInsertNum.Start();
            //等待后台线程释放主线程的阻塞
            mre.WaitOne();
            /*后台线程找到了素数,并对result赋值,关闭将数字不断入队的线程。
             * 至于线程池中的任务不必操心。后台自然会自动处理。因为标签已经置为isover了。
            */
            thInsertNum.Abort();
           
            //返回这个值,它是素数
            return result;
        }
        public static BigInteger CreatePrimeNum2(int length)
        {
            //这是以单线程形式进行运算的例子,通过测试,显然,它比较慢。
            BigInteger primeNum = CreateRandomNum(length);
            int i = 0;
            do
            {
                i++;
                primeNum += 2;
            }
            while (!primeNum.IsProbablePrime());
            return primeNum;
        }
        private static void ThreadMethod(object obj)
        {
            //寻找素数并赋值给result的线程中运行的方法
            while (!isOver)
            {
                //将队列中的数出队,使用队列是为了避免同一个数被重复运算。防止线程冲突。
                BigInteger tempNum = quePrime.DeQueue();
                if (tempNum.IsProbablePrime())
                {
                    //找到了素数,对全局变量赋值
                    result = tempNum;
                    //释放进程锁,此后主进程将会把这个result返回
                    ManualResetEvent mre = (ManualResetEvent)obj;
                    mre.Set();
                    isOver = true;
                    break;
                }
            }
        }
        //此类来自维基百科
        public static bool IsProbablePrime(this BigInteger source)
        {
            if (PreCheckPrime(source) != 0)
            {
                return false;
            }
            int certainty = 4;//确认4次差不多了
            //if (source == 2 || source == 3)
            //    return true;
            //if (source < 2 || source % 2 == 0)
            //    return false;
            //就本类的随机数发生器,以上情况不可能出现
           
            BigInteger d = source - 1;
            int s = 0;
            while (d % 2 == 0)
            {
                d /= 2;
                s += 1;
            }
                    
            byte[] bytes = new byte[source.ToByteArray().LongLength];
            BigInteger a;
            for (int i = 0; i < certainty; i++)
            {
                do
                {                   
                    rng.GetBytes(bytes);
                    a = new BigInteger(bytes);
                }
                while (a < 2 || a >= source - 2);
                BigInteger x = BigInteger.ModPow(a, d, source);
                if (x == 1 || x == source - 1)
                    continue;
                for (int r = 1; r < s; r++)
                {
                    x = BigInteger.ModPow(x, 2, source);
                    if (x == 1)
                        return false;
                    if (x == source - 1)
                        break;
                }
                if (x != source - 1)
                    return false;
            }
            return true;
        }
        //在使用RabinMiller算法前先进行素数的筛选
        public static int PreCheckPrime(BigInteger bigNum)
        {
            //检验被3,5,7,17特殊数字整除
            string strBigNum = bigNum.ToString();
            int everyDigit = 0;//这个数字除个位的其它位之和
            for (int i = 0; i < strBigNum.Length - 1; i++)
            {
                everyDigit += int.Parse(strBigNum[i].ToString());
            }
            int lastDigit = int.Parse(strBigNum[strBigNum.Length - 1].ToString());
            //每一位上数字之和能被3整除,那么这个数就能被3整除。
            if ((everyDigit + lastDigit) % 3 == 0)
            {
                return 3;
            }
            //个位上是0或5的数都能被5整除。
            if (lastDigit.Equals(5))
            {
                return 5;
            }
            int[] shortPrimes = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999 };
            for (int i = 0; i < shortPrimes.Length; i++)
            {
                if (bigNum % shortPrimes[i] == 0)
                {
                    return shortPrimes[i];
                }
            }
            return 0;
        }
    }
    //这是一个阻塞队列
    public class BlockQueue<T>
    {
        public readonly int SizeLimit = 0;
        private Queue<T> _inner_queue = null;
        public int Count
        {
            get { return _inner_queue.Count; }
        }
        private ManualResetEvent _enqueue_wait = null;
        private ManualResetEvent _dequeue_wait = null;
        public BlockQueue(int sizeLimit)
        {
            this.SizeLimit = sizeLimit;
            this._inner_queue = new Queue<T>(this.SizeLimit);
            this._enqueue_wait = new ManualResetEvent(false);
            this._dequeue_wait = new ManualResetEvent(false);
        }
        public void EnQueue(T item)
        {
            if (this._IsShutdown == true) throw new InvalidCastException("Queue was shutdown. Enqueue was not allowed.");
            while (true)
            {
                lock (this._inner_queue)
                {
                    if (this._inner_queue.Count < this.SizeLimit)
                    {
                        this._inner_queue.Enqueue(item);
                        this._enqueue_wait.Reset();
                        this._dequeue_wait.Set();
                        break;
                    }
                }
                this._enqueue_wait.WaitOne();
            }
        }
        public T DeQueue()
        {
            while (true)
            {
                if (this._IsShutdown == true)
                {
                    lock (this._inner_queue) return this._inner_queue.Dequeue();
                }
                lock (this._inner_queue)
                {
                    if (this._inner_queue.Count > 0)
                    {
                        T item = this._inner_queue.Dequeue();
                        this._dequeue_wait.Reset();
                        this._enqueue_wait.Set();
                        return item;
                    }
                }
                this._dequeue_wait.WaitOne();
            }
        }
        public void Clear()
        {
            this._inner_queue.Clear();
            this._dequeue_wait.Reset();
            this._enqueue_wait.Set();
        }
        private bool _IsShutdown = false;
        public void Shutdown()
        {
            this._IsShutdown = true;
            this._dequeue_wait.Set();
        }
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-02-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档