LoginSignup
2
1

More than 3 years have passed since last update.

任意の素数2つからOpenSSL で使える rsa 秘密鍵を作成する ruby スクリプト

Posted at

背景

ちょっとした RSA 秘密鍵を、本来的なその変数である素数p, qと、公開乗数eを指定して自動で作成したいと思いたち、それを行なうスクリプトを記述した。

その際に、 Ruby は
1. 整数(Integer)がデフォルトで任意精度
2. OpenSSL が標準ライブラリに含まれるので、 DER まわりの処理が他のライブラリを必要としない

で、親和性が高かったので、これを用いた。

スクリプト本体

create-rsa-private.rb

#!/usr/bin/env ruby

require 'openssl'

prime1 = ARGV[0].to_i
prime2 = ARGV[1].to_i
e = (ARGV[2] || 0x10001).to_i

# 以上から、 rsa の key を作る。

n = prime1 * prime2

module ExtendedEuclid
  # args: a, b
  # return: [gcd(a,b), x, y]
  #         s.t. x*a + y*b = gcd(a,b)
  def self.call(a, b)
    return [a, 1, 0] if b == 0

    # a = q*b + r
    # <=> r = a - q*b
    q, r = a.divmod(b)

    # s*b + t*r == gcd
    gcd, s, t = call(b, r)
    # s*b + t*(a- q*b) == gcd
    # t*a + (s - t*q)*b == gcd

    [gcd, t, s - t*q]
  end
end

carmichael = (prime1 - 1).lcm(prime2 - 1)
gcd, _, d = ExtendedEuclid.call(carmichael, e)
raise "e and lcm(p-1, q-1) not coprime" unless gcd == 1
d = d % carmichael

exp1 = d % (prime1 - 1)
exp2 = d % (prime2 - 1)

gcd, _, prime2_inv = ExtendedEuclid.call(prime1, prime2)
raise "p and q not coprime" unless gcd == 1
prime2_inv = prime2_inv % prime1

priv_key = OpenSSL::ASN1::Sequence.new(
  [0, n, e, d, prime1, prime2, exp1, exp2, prime2_inv].map(&OpenSSL::ASN1::Integer.method(:new))
)

print(priv_key.to_der)

利用法

# 生成されるのは der なので
$ ./create-rsa-private.rb 103 131 > private.der

# pem が良い場合は openssl で変換する
$ openssl rsa -in ./private.der -inform DER > private.pem

# RSA 秘密鍵として適格か確認
$ openssl rsa -in ./private.pem -text -noout -check
Private-Key: (14 bit)
modulus: 13231 (0x33af)
publicExponent: 65537 (0x10001)
privateExponent: 673 (0x2a1)
prime1: 101 (0x65)
prime2: 131 (0x83)
exponent1: 73 (0x49)
exponent2: 23 (0x17)
coefficient: 64 (0x40)
RSA key ok

補足

RSA 秘密鍵の定義

の ASN1 に定義が書いてあり、それをそのまま計算すれば良い。具体的には、

version:         0
modulus:         n == p * q
publicExponent:  e == 65537  (==0x10001)
privateExponent: d == e^-1 mod LCM(p-1, q-1)
prime1:          p
prime2:          q
exponent1:       d mod (p-1)
exponent2:       d mod (q-1)
coefficient:     q^(-1) mod p

な ASN1 の SEQUENCE であれば良い。

素数以外をつっこみたいとき

上で記述した秘密鍵の定義上、pq が互いに素であって、かつ lcm(p-1, q-1)e が互いに素であれば、例えば「合成数をベースにしてしまった RSA 秘密鍵」も割と問題なく作れたりする。

擬素数をつっこんで RSA がそのときどのように動作するのか調べたいときにも使える。(自分はむしろこっちがやりたくてこのスクリプトを書いていた)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1