web-dev-qa-db-ja.com

短いRSAキーのクラッキング

次のRSAキーが与えられた場合、pおよびqの値が何であるかをどのように判断しますか?

Public Key: (10142789312725007, 5)
Private Key: (10142789312725007, 8114231289041741)
50
Donald Taylor

あなたの先生はあなたに与えた:

公開鍵:(10142789312725007、5)

つまり

n = 10142789312725007
e = 5 

ここで、nはモジュラスであり、eは公開指数です。

さらに、あなたは与えられています

秘密鍵:(10142789312725007、8114231289041741)

という意味

 d = 8114231289041741

ここで、dは秘密にしておくべき復号化指数です。

「n」を「p」および「q」素因数に分解する方法を知ることにより、RSAを「破壊」できます。

n = p * q

最も簡単な方法は、nの平方根のすぐ下から始まるすべての奇数をチェックすることです。

Floor[Sqrt[10142789312725007]] = 100711415

4回の試行で最初の要素を取得します。

10142789312725007 mod 100711415 = 100711367
10142789312725007 mod 100711413 = 100711373
10142789312725007 mod 100711411 = 100711387
10142789312725007 mod 100711409 = 0 <-- Winner since it evenly divides n

だから私たちは

 p = 100711409

さて、

 q = n / p 
   = 10142789312725007 / 100711409
   = 100711423

何でこれが大切ですか? dが特別な数値であるためです

d = e^-1 mod phi(n)
  = e^-1 mod (p-1)*(q-1)

これを確認できます

d * e = 40571156445208705 = 1 mod 10142789111302176

プレーンテキストメッセージmがある場合、暗号文は

c = m^e mod n

そしてあなたはそれを解読する

m = c^d = (m^e)^d = (m^(e*d)) = (m^(e*e^-1)) = m^1 (mod n)

たとえば、教師の公開鍵を使用してメッセージ123456789を「暗号化」できます。

m = 123456789

これにより、次の暗号文が得られます。

c = m^e mod n 
  = 123456789^5 mod 10142789312725007
  = 7487844069764171

(「m」の値が小さい場合はnを超えないため、「e」は実際にはもっと大きくする必要があります)

とにかく、今「c」があり、「d」でそれを逆にすることができます

m = c^d mod n
  = 7487844069764171^8114231289041741 mod 10142789312725007
  = 123456789

明らかに、「7487844069764171 ^ 8114231289041741」は128,808,202,574,088,302桁であるため、直接計算することはできません。したがって、 モジュラーべき乗 トリックを使用する必要があります。

「実世界」では、nは明らかにはるかに大きいです。 HTTPSが617桁のnおよびeの65537、私のブログ投稿「 HTTPS接続の最初の数ミリ秒 」を参照してください。

125
Jeff Moser

これを見るのは比較的簡単な方法です(手で実行できる方法)。数値を完全に因数分解する場合、考慮する必要がある最高の要因はsqrt(N)です。

sqrt(10142789312725007) = 100711415.9999997567

これより下の最初の素数は100711409で、sqrt(N)の6つ下にあります。

10142789312725007 / 100711409 = 100711423 

したがって、これらはNの2つの要因です。あなたの教授はそれを非常に簡単にしました-トリックは誰もsmall pまたはqを選択しないことを認識するので、下からチェックを開始します(python誰かが投稿したスクリプト)は悪い考えです。手作業で実用的になる場合、大きなpとqはsqrt(N)の近くになければなりません。

15
ine

nn、およびeを指定したdの因数分解の問題を解決するためのさまざまな高速アルゴリズムがあります。このようなアルゴリズムの適切な説明は、Applied Cryptography Handbook、 Chapter 8 、セクション8.2.2にあります。これらの章はオンラインで無料ダウンロードできます こちら

11
James K Polk

Wolframalpha は、係数が100711409および100711423であることを示します

単純にPythonでブルートフォースを行うスクリプトを作成しました。amdfanが指摘したように、先頭から開始するのがより良いアプローチです。

p = 10142789312725007
for i in xrange(int(p**0.5+2), 3, -2):
    if p%i == 0:
        print i
        print p/i
        break

これは大幅に改善される可能性がありますが、問題なく機能します。素因数をテストするだけで改善できますが、あなたのような小さな値の場合はこれで十分です。

10
Juri Robl

Java Applied Cryptography Handbookの高速因数分解メソッドの実装 8章 セクション8.2.2(見つけたGregSに感謝):

/**
 * Computes the factors of n given d and e.
 * Given are the public RSA key (n,d)
 * and the corresponding private RSA key (n,e).
 */
public class ComputeRsaFactors
{
    /**
     * Executes the program.
     *
     * @param args  The command line arguments.
     */
    public static void main(String[] args)
    {
        final BigInteger n = BigInteger.valueOf(10142789312725007L);
        final BigInteger d = BigInteger.valueOf(5);
        final BigInteger e = BigInteger.valueOf(8114231289041741L);

        final long t0 = System.currentTimeMillis();

        final BigInteger kTheta = d.multiply(e).subtract(BigInteger.ONE);
        final int exponentOfTwo = kTheta.getLowestSetBit();

        final Random random = new Random();
        BigInteger factor = BigInteger.ONE;
        do
        {
            final BigInteger a = nextA(n, random);

            for (int i = 1; i <= exponentOfTwo; i++)
            {
                final BigInteger exponent = kTheta.shiftRight(i);
                final BigInteger power = a.modPow(exponent, n);

                final BigInteger gcd = n.gcd(power.subtract(BigInteger.ONE));
                if (!factor.equals(BigInteger.ONE))
                {
                    break;
                }
            }
        }
        while (factor.equals(BigInteger.ONE));

        final long t1 = System.currentTimeMillis();

        System.out.printf("%s %s (%dms)\n", factor, n.divide(factor), t1 - t0);
    }


    private static BigInteger nextA(final BigInteger n, final Random random)
    {
        BigInteger r;
        do
        {
            r = new BigInteger(n.bitLength(), random);
        }
        while (r.signum() == 0 || r.compareTo(n) >= 0);
        return r;
    }
}

典型的な出力は

100711423 100711409 (3ms)
4
starblue

RSAの定義は、モジュラスn = pqnを知っているので、乗算してpを生成する2つの数値qnを見つける必要があります。 pqが素数であることがわかっているので、これが素因数分解問題です。

比較的小さな数に対しては総当たりでこれを解決できますが、RSAの全体的なセキュリティは、一般にこの問題が扱いにくいという事実に依存します。

4
Cameron Skinner

これらの2つの論文はおそらく役に立つかもしれません

私は継続的な分数に関するいくつかの基本的な研究をしていたときにそれらに出くわした。

3
user498884

これを行うアルゴリズムは次のとおりです(これはどのコンピューターでも簡単にファクタリングできるこの小さなものだけでなく、どの例でも機能します)。

ed - 1phi(n) = (p-1)(q-1)の倍数なので、少なくとも4の倍数です。
ed - 1は、2^7 * 316962159728193に等しい40571156445208704として計算でき、s=7およびt = 316962159728193を呼び出します。 (一般的に、偶数は奇数の2のべき乗です)。ここで、[2,n-1)をランダムに選択し、(nを法とする連続した2乗法により)a^t (mod n), a^(2t) (mod n), a^(4t) (mod n)..シーケンスを最大a^((2^7)*t) (mod n)まで計算します。最後のシーケンスは、eおよびdの構築により、1.

次に、そのシーケンスの最初の1を探します。その前のものは+1または-1(1、mod nのささいなルート)であり、別のa、または+1または-1mod nと等しくないいくつかの番号xでやり直します。後者の場合、gcd(x-1, n)nの非自明な除数であるため、pまたはqであり、完了です。ランダムなaが約0.5の確率で機能することを示すことができるので、数回の試行が必要ですが、一般的にはそれほど多くありません。

3
Henno Brandsma

ネクロマンシーで申し訳ありませんが、友人がこれについて私に尋ねました、そして、彼をここに指した後、私は答えのどれも本当に好きではないことに気づきました。モジュラスを因数分解して素数(pおよびq)を取得した後、(p-1)*(q-1)であるtotientを見つける必要があります。

ここで、プライベート指数を見つけるために、パブリック指数の逆数をtotientで見つけます。

public_exponent * private_exponent = 1 mod totient

これで、秘密鍵が手に入りました。因数分解を除くこのすべては、巨大な整数に対してほぼ瞬時に実行できます。

私はいくつかのコードを書きました:

// tinyrsa.c
//
// apt-get install libgmp-dev
// yum install gmp-devel
//
// gcc tinyrsa.c -o tinyrsa -lm -lgmp

#include<stdio.h>
#include<gmp.h>

int main()
{
  // declare some multi-precision integers
  mpz_t pub_exp, priv_exp, modulus, totient, fac_p, fac_q, next_prime;

  mpz_init_set_str(pub_exp,"5",10);
  mpz_init_set_str(modulus,"10142789312725007",10);

  mpz_init(priv_exp);
  mpz_init(totient);
  mpz_init(fac_p);
  mpz_init(fac_q);

  // now we factor the modulus (the hard part)
  mpz_init(next_prime);
  mpz_sqrt(next_prime,modulus);
  unsigned long removed=0;
  while(!removed)
  {
    mpz_nextprime(next_prime,next_prime);
    removed=mpz_remove(fac_p,modulus,next_prime);
  }

  mpz_remove(fac_q,modulus,fac_p);
  // we now have p and q

  // the totient is (p-1)*(q-1)  
  mpz_t psub, qsub;
  mpz_init(psub);
  mpz_init(qsub);

  mpz_sub_ui(psub,fac_p,1);
  mpz_sub_ui(qsub,fac_q,1);
  mpz_mul(totient,psub,qsub);

  // inverse of the public key, mod the totient..
  mpz_invert(priv_exp,pub_exp,totient);

  gmp_printf("private exponent:\n%Zd\n",priv_exp);

}

私が使用した因数分解アルゴリズムは愚かですが、簡潔なので、そこに一粒の粒があります。この特定の例では、コードはほぼ瞬時に実行されますが、これは主に、問題のインストラクターが2つの素数を連続して使用する例を提供したためです。これはRSAにとって現実的ではありません。

愚かな反復検索を排除したい場合は、実際の因数分解アルゴリズムを使用し、妥当な時間内に最大で約256ビットのキーを因数分解できます。

2
pierce

Quadratic Sieve について読むことをお勧めします。自分で実装する場合、これは間違いなく価値があります。原則を理解していれば、すでに何かを得ています。

1
Yuval F

モジュラスを因数分解する必要があります。これは公開鍵の最初のパラメータ10142789312725007です。ブルートフォースは実行します(因数であれば3からsqrt(n)までの奇数をすべてチェックします)。

数値が大きすぎて従来の整数(64ビットでも)に収まらないため、任意の長さの整数をサポートする数値ライブラリが必要になる場合があります。 Cには、GMPとMPIR(よりWindowsフレンドリー)があります。 PHPには、Bignumがあります。 Pythonには組み込みのものが付属しています-組み込み整数データ型は既に任意の長さです。

0
Seva Alekseyev

大規模な準素数の素因数分解またはふるい分けのいずれについても半素数の素因数分解に必要な因子分解について多くの悪い推測があります。私のPCでは64ビットは1〜2秒かかり、一般的に256ビットは2日未満です

0
Mick Press