在C#中解密RSA编码的消息

时间:2017-09-12 19:29:06

标签: c# encryption rsa primes

作为一名IT老师,我想向学生展示RSA算法的工作原理。我还想告诉他们,通过迭代所有可能的素数来“乱砍”它需要永远。

加密和解密对于素数而言非常合适< 1000.当我用略大的素数执行相同的算法时,解密结果是错误的。

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);

    }

}

}

2 个答案:

答案 0 :(得分:1)

你的问题在于数学。

召回const mp_obj_type_t pyb_led_type = { { &mp_type_type }, .name = MP_QSTR_LED, .print = led_obj_print, .make_new = led_obj_make_new, .locals_dict = (mp_obj_t)&led_locals_dict, }; ,这意味着e*d == 1 mod phi(n)。在您的实现中,您假设e*d = 1 + k*phi(n)总是为2.这个假设是错误的。

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

如果您在代码中放置一个断言以检查d,那么您很容易看到exp*d = 1 + k*phi(n)的启发式工作何时起作用,何时起作用。

使用扩展的欧几里德算法为k获得正确的解决方案。

此外:

“我还想向他们展示,通过迭代所有可能的素数,'黑客攻击'需要永远。”很高兴让他们入侵,一旦他们感到沮丧并意识到它无法发挥作用,那么你可以向他们展示一些小数学可以提前向他们证明。 prime number theorem向我们展示了素数的密度。你可以采用2 ^ 1024数量级的素数,并告诉他们这个大小的数量级为2 ^ 1014.5。然后问他们每秒可以做多少次尝试,并通过这种天真的方法计算他们要破解的年数(或者你可以采用查看存储的方法来获取所有质数的表)。然后,这可以导致更好的解决方案,如数字字段筛。哦,真有趣!

答案 1 :(得分:0)

好的,这对我来说非常愚蠢......非常感谢你的想法,我一定会看看这个定理!

现在可以使用

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;
    }