Python で RSA 公開鍵暗号をなぞってみる

こんにちは,yaitaimo です.

この記事は CAMPHOR- Advent Calendar 2015 の3日目の記事です.

RSA 公開鍵暗号は,一度触れて見たがよくわからなかった,という人も居るのでは無いでしょうか.今回はそんな皆さんのために,数学的に一番簡単な筋をたどって,一連の流れを説明したいと思います.

納得感を持って読み終わっていただけたら幸いです.

Python 3 を使います.

1. RSA 公開鍵暗号とは

公開鍵暗号は,暗号化と復号に同じ鍵を用いる共通鍵暗号と違い,世界に公開する公開鍵と自分しか知らない秘密鍵の2つの鍵を用いる.

この2つの鍵は,

  • 公開鍵で暗号化したものは,秘密鍵でしか復号できない
  • 秘密鍵で暗号化したものは,公開鍵でしか復号できない

という性質を持っている.

これをうまく利用することで,秘密情報の伝達や認証を行うことが出来る.
今回はこの内の秘密情報の伝達を取り上げて実装を行う.

秘密情報の伝達

  1. BさんがAさんにある機密データを受け取りたい場合は,Aさんの公開鍵を使ってそのデータを暗号化してからAさんに送る.
  2. Aさんは秘密鍵を使ってそれを復号し,データを手に入れる.

RSA暗号は上記の公開鍵を具体的に実現したもので,桁数が大きい合成数の素因数分解が困難であることを安全性の根拠としたものである.

2. 必要な数学の知識と実装

最大公約数(ユークリッドの互除法)

「2つの正の整数に共通な約数のうち最大のもの」

例えば gcd(19, 7) を求める場合,

19 = 2 \times 7 + 5
7 = 1 \times 5 + 2
5 = 2 \times 2 + 1
2 = 2 \times 1

を計算して,gcd(19, 7) = 1 が得られる.

最小公倍数

「2つの正の整数の共通な倍数のうち最小のもの」

例えば lcm(15, 3) を求める場合,
15 \times 3 / gcd(15, 3) = 15
を計算して,lcm(15, 3) = 15 が得られる.

拡張ユークリッドの互除法

x, y を正の整数とし,c = gcd(x, y) とするとき,ax + by = c となる整数 a, b が存在し,a, b は計算することが出来る」

x = 19, y = 7c = gcd(x, y) = 1)のとき a, b を求める場合,

1x + 0y = 19 …(1)
0x + 1y = 7 …(2)
1x - 2y = 5 …(3) = (1) – (2) * 2
-1x + 3y = 2 …(4) = (2) – (3)
3x - 8y = 1 …(5) = (3) – (4) * 2

を計算して,a = 3, b = -8 が得られる.

モジュロ演算

x \bmod{n} = a のように書くとき,xn で割った余りは a であることを意味する
また,x \equiv a \pmod{n} のように書くとき,xan で割った余りが等しいことを意味する.

3. RSA暗号の実装

3.1 ユーザの鍵生成

  1. 2素数 p, q を定め, n = pq を計算する.
  2. \lambda (n) = lcm (p-1, q-1) に対して, \lambda (n) と互いに素で \lambda (n) より小さな正の整数 e を生成し,ed \equiv 1 \pmod{\lambda(n)} を満たす d を求める.

以上より,公開鍵 e, n と秘密鍵 d を得る.

例:
p = 7, q = 11 の場合,n = 77 が得られる.
\lambda (n) = lcm(7 -1, 11 - 1) = lcm(6, 10) = 30 であり,これと互いに素となるよう,e = 13 とする.

ここで,拡張ユークリッドの互除法を利用して,
ed + \lambda (n)f = 1 …(b)
を解くことを考える.ただし,e\lambda (n) は互いに素であるため,右辺は 1 となっている.
上式において,モジュロ \lambda (n) を取ると,
ed + \lambda (n)f \equiv 1 \pmod{\lambda (n)}
となるが,これは
ed \equiv 1 \pmod{\lambda (n)}
と整理できる.よって,(b)を解くことで,d を得られることがわかった.
ただし,拡張ユークリッドの互除法では負数が出力されることもあるため,d にはモジュロ \lambda (n) を取り,正の値にして用いる.

このようにして,d = 7 が得られた.

3.2 暗号化

平文 m を公開鍵である e, n を用いて暗号化する.
c = m^e \bmod{n}

例:
m = 15e = 13, n = 77 で暗号化とすると,c = 64 が得られる.

3.3 復号

暗号文 c を秘密鍵である d を用いて復号する.
m = c^d \bmod{n}

例:
c = 64d = 7 で復号すると,m1 = 15 が得られる.

4. おわりに

さくっと書いてきましたが,内容については理解してもらえたでしょうか.
興味が出てきた人は,RSAについて調べてみてください.
高速化・効率化するさまざまな手法があるので興味深いです.

明日は ryota-ka です.お楽しみに.


Python で RSA 公開鍵暗号をなぞってみる」への2件のフィードバック

  1. 師子乃

    初めまして、情報処理の勉強をしている者です。

    RSAの解説、とても興味深くかったです!

    これからも色々と学ばせて下さい!

    よろしくお願いいたします。

    返信
    1. yaitaimo 投稿作成者

      師子乃さん

      yaitaimo です.コメントは励みになるので,とてもありがたいです!
      こちらこそ,どうぞよろしくお願いいたします.

      返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です