【问题标题】:Decrypting RSA encoded message in C#在 C# 中解密 RSA 编码的消息
【发布时间】:2018-02-21 08:47:49
【问题描述】:

作为一名 IT 教师,我想向我的学生展示 RSA 算法的工作原理。我还想向他们展示通过迭代所有可能的素数来“破解”它需要很长时间。

对于

Eg:
p, q are primes  
n = p * q  
phi = (p-1) * (q -1)  
d = (1 + (k * phi)) / e;  
**encryption:**  
c = (msg ^ e) % n  
**decryption**  
message = c ^ d % n;  

对于 p = 563 和 q = 569,解密工作正常。
另一方面,对于 p = 1009 和 q = 1013,解密后的消息 =/= 原始消息。

我认为错误在于计算私有指数“d”。我用 BigIntegers 替换了所有 int,但这并没有改变任何事情。有人有想法吗?

class RSA
{
    private BigInteger primeOne;
    private BigInteger primeTwo;
    private BigInteger exp;
    private BigInteger phi;
    private BigInteger n;
    private BigInteger d;
    private BigInteger k;


    private void calculateParameters(){
        // First part of public key:
        this.n = this.primeOne * this.primeTwo;
        // Finding other part of public key.
        this.phi = (this.primeOne - 1) * (this.primeTwo - 1);
        //Some integer k
        this.k = 2;
        this.exp = 2;

        while (this.exp < (int) this.phi)
        {
            // e must be co-prime to phi and
            // smaller than phi.

            if (gcd(exp, phi) == 1)
                break;
            else
                this.exp++;
        }

        this.d = (BigInteger) (1 + (this.k * this.phi)) / this.exp; ;
    }

    // Return greatest common divisors
    private static BigInteger gcd(BigInteger a, BigInteger b)
    {
        if (a == 0)
            return b;
        return gcd(b % a, a);
    }

    //Encryption algorithm RSA
    public string Encrypt(string msg)
    {
        calculateParameters();
        BigInteger encryptedNumber = BigInteger.Pow(BigInteger.Parse(msg),(int) this.exp) % this.n;
        // Encryption c = (msg ^ e) % n
        return Convert.ToString(encryptedNumber);

    }

    public string Decrypt(string encrypted)
    {

        BigInteger intAlphaNumber = BigInteger.Parse(encrypted);
        BigInteger decryptedAlphaNumber = BigInteger.Pow(intAlphaNumber,(int) this.d) % n;
        return Convert.ToString(decryptedAlphaNumber);

    }

}

}

【问题讨论】:

  • BigInteger.Parse(msg) 是否符合您的预期?如果消息是字母数字怎么办?
  • 你的实现中总是有 k=2。所以简而言之,你计算 d 的启发式方法并不总是有效。
  • 在我的原始代码中,我将字母转换为数字,但我保留了它。我只想加密数字 89(=“HI”)。当我用大素数对其进行加密时,数字会被错误地解密。
  • 当 n>2^16 时,需要担心 32 位 int 溢出。
  • 您可能想单独使用 ModPow 而不是 Pow 和 Mod。它的扩展性要好得多。

标签: c# encryption rsa primes


【解决方案1】:

你的问题在于数学。

回忆e*d == 1 mod phi(n),这意味着e*d = 1 + k*phi(n)。在您的实现中,您假设 k 始终为 2。这种假设是错误的。

为了证明,请考虑p = 1009 和q = 1013 的错误情况。在这种情况下,exp 根据您的算法选择为 5。 k 对应的正确值是 4,所以 d 应该是 816077。但是,您的算法错误地将 d 计算为 408038。

如果您在代码中添加一个断言来检查 exp*d = 1 + k*phi(n),那么您将很容易看到您对 k 的启发式何时有效,何时无效。

使用扩展欧几里得算法得到d 的正确解。

还有:

“我还想向他们展示,通过迭代所有可能的素数来‘破解’它需要很长时间。”让他们破解很好,一旦他们感到沮丧并意识到它不起作用,那么你可以向他们展示一点数学可以提前向他们证明这一点。 prime number theorem 向我们展示了素数的密度。您可以以 2^1024 数量级的素数为例,向他们展示这种大小的素数数量级为 2^1014.5。然后问他们每秒可以尝试多少次,并通过这种简单的方法计算他们破解所需的年数(或者您可以采用查看存储以查找所有素数表的方法)。然后这可以带来更好的解决方案,例如数字字段筛。哦,太有趣了!

【讨论】:

    【解决方案2】:

    好吧,我真是太愚蠢了……非常感谢你的想法,我一定会研究一下这个定理!

    现在可以使用了

    private static BigInteger ModInverse(BigInteger a, BigInteger n)
        {
            BigInteger t = 0, nt = 1, r = n, nr = a;
    
            if (n < 0)
            {
                n = -n;
            }
    
            if (a < 0)
            {
                a = n - (-a % n);
            }
    
            while (nr != 0)
            {
                var quot = r / nr;
    
                var tmp = nt; nt = t - quot * nt; t = tmp;
                tmp = nr; nr = r - quot * nr; r = tmp;
            }
    
            if (r > 1) throw new ArgumentException(nameof(a) + " is not convertible.");
            if (t < 0) t = t + n;
            return t;
        }
    

    【讨论】:

      猜你喜欢
      • 2018-02-13
      • 1970-01-01
      • 2012-01-18
      • 2020-08-05
      • 2011-02-08
      • 2018-07-17
      • 1970-01-01
      • 2017-02-16
      相关资源
      最近更新 更多