ブログ未満のなにか

ブログなのか誰にも分からない

秘密鍵をpem形式にする

ctfをやっている最中に、求めた秘密鍵Wiresharkに食わせて
暗号化された通信を復号する必要があった.

秘密鍵の値や素数の値は分かっているので、フォーマットを合わせればいけるだろと簡単に考えてたら結構時間を費やしてしまった。

wiresharkは、opensslコマンドでデフォルトで生成されるpem形式を扱うことができる。
pem形式のフォーマットに関しては、こちらを参考にした。
RSA 秘密鍵/公開鍵ファイルのフォーマット - bearmini's blog

とても分かりやすくスクリプトを書く際にとても役立った。感謝

以下が、pem形式の秘密鍵ファイルを生成するpythonでのスクリプト
ファイルに格納される情報は、e、p、qさえあれば全て計算できるが、割愛している

# s: integer, return "00ABFF"
def my_hex(s):
    s = hex(s)[2:]
    if s[-1] == 'L':
        s = s[:-1]
    if len(s) % 2 == 0:
        return s
    else:
        return '0'+s

# s: integer, return byte length
def getLength(s):
    he = my_hex(s)
    le = len(he) / 2
    return le


# s: integer, return str_hex
def setByteStream(s):
    buf = "02"

    length = getLength(s)

    if length >= 0b10000000:
        lengthlength = getLength(length + 1)
        buf += my_hex(0b10000000 | lengthlength)
        buf += my_hex(length +1)
        buf += '00' + my_hex(s)
    else:
        buf += my_hex(length)
        buf += my_hex(s)
    return buf

def calcLength(buf):
    length = len(buf) / 2
    
    b = ""
    if length >= 0b10000000:
        lengthlength = getLength(length)
        b += my_hex(0b10000000 | lengthlength)
        b += my_hex(length)
    else:
        b += my_hex(length)

    return b


e = 65537
d = 100
p = 3
q = 5
n = p * q
inv_q = 10


f = open("privatekey.pem", "wb")

f.write("-----BEGIN RSA PRIVATE KEY-----\n")

version = "020100"
modules = setByteStream(n)
pubExp = setByteStream(e)
priExp = setByteStream(d)
prime1 = setByteStream(p)
prime2 = setByteStream(q)
exp1 = setByteStream(d % (p-1))
exp2 = setByteStream(d % (q-1))
coefficient = setByteStream(inv_q)

buf = version + modules + pubExp + priExp + prime1 + prime2 + exp1 + exp2 + coefficient

sequence = "30" + calcLength(buf)

buf = sequence + buf
buf = al.decode("hex")
buf = al.encode("base64")

f.write(buf)

f.write("-----END RSA PRIVATE KEY-----\n")

f.close()