ryuto-u
@ryuto-u (S R)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

単一換字式暗号実装

単一換字式暗号実装

この暗号を実装したのですが、この暗号はどういった場面で応用されるのでしょうか?

一応、実装内容を提示させて頂きます。

手順

鍵生成
1. 素数pとqを選ぶ
2. n=pqとphi=gcd(p−1,q−1)を計算する。phi=オイラー関数 3. phiと互いに素でかつphiより小さい数eを選ぶ。
4. d=1/e mod (phi)を計算する。秘密鍵をdを公開鍵e,Nとする。 暗号化(
暗号文は数字にします。)
5. c=m^e mod (N)を計算して、cを出力する。
復号
6. m=c^d mod (N)を計算して、mを出力する。

ライブラリ

import random
import math

素数判定と取得

十分に大きい素数p,qを求めます。
ここでは11からNまでの素数をランダムに生成します。 S=2に関しては素数判定の際の方法で割り切れるかを判定しています。そして次の素数を判定します。

def sympy_prime( N ):
  while True:
    n = (random.randint( 11, N ))
    s = 2
    flag = True
    while s*s <= n and flag:
      if n % s == 0:
        flag = False
      s += 1
    if flag:
      return n

鍵生成

Kをセキュリティパラメーターとします。 オイラー関数ではpが素数であるとき𝜑(p)=p−1であること、および、p,qが互いに素であるとき(共通の素因数を持たない) 𝜑(pq)=𝜑(p)𝜑(q)が成り立ちます。
その次に、𝜑(N)と互いに素であるe(1<e<𝜑(N))をランダムに生成します。
次にed≡1 mod 𝜑(N)となるdを求めます。この値を求めるには、拡張ユークリッドの互除法を使用します。
d=1/e mod (phi)を計算する。
そしてdが求まります。
dが秘密鍵、N,eが公開鍵となります。

def generate_keys( k ):
  b = 1 << int( k/2 )
  e = 7
  flag = True
  while flag:
    p = sympy_prime( b )
    q = p
    while p == q:
      q = sympy_prime( b )
    N = p * q
    phi = ( p-1 ) * ( q-1 )
    d = gcd( phi, e )
    if phi%e != 0:
      flag = False
  return ( N, e ), d

暗号化

公開鍵で暗号化をします。
具体的に平文をmとします。
そしてC ≡m^e mod (N)を求めます。
暗号化時Cは、 m^eをNで割ったときの余りが送りたいメッセージmを暗号化して送る数字になります。

複号化

秘密鍵で複合化をします。
暗号化された𝑐を復号するには、m′≡c^d mod (N)を求めたものが復号された値になります。

def encrypt( m, public_key ):
  cipher = []
  N, e = public_key
  for l in m:
    c = ord(l)
    for s in range( e-1 ):
      c = ( c*ord(l) ) % N
    cipher.append( c )
  return cipher

def decrypt( c, public_key, private_key ):
  decode = ''
  N = public_key[0]
  for c1 in c:
    m = c1
    for s in range( private_key-1 ):
      m = ( m*c1 ) % N
    decode += chr( m )
  return decode
if __name__ == '__main__':
  public_key, private_key = generate_keys(8)
  plain_text = 'sato'
  cipher = encrypt( plain_text, public_key )
  decode = decrypt( cipher, public_key, private_key )
  print( 'N =', public_key[0] )
  print( 'e =', public_key[1] )
  print( 'd =', private_key, '\n' )
  print( 'plain        → cipher            → decode' )
  for s in range( len(plain_text) ):
    print( plain_text[s], ord(plain_text[s]), '(', format(ord(plain_text[s]), '08b'), ')→',
     cipher[s], '(', format(cipher[s], '08b'), ')→',
     ord(decode[s]), '(', format(ord(decode[s]),'08b'), ')', decode[s] )

実装結果:satoが復号化されました。

N = 143
e = 7
d = 103 

plain        → cipher            → decode
s 115 ( 01110011 )→ 80 ( 01010000 )→ 115 ( 01110011 ) s
a 97 ( 01100001 )→ 59 ( 00111011 )→ 97 ( 01100001 ) a
t 116 ( 01110100 )→ 129 ( 10000001 )→ 116 ( 01110100 ) t
o 111 ( 01101111 )→ 45 ( 00101101 )→ 111 ( 01101111 ) o
0

この「意見交換」として投稿されている本投稿は,もしかしたら普通の記事としてリリースするものだったのですか?特に意見交換したいと考えているような箇所への記述が見られません.

お節介で何かアドバイスがあるとすれば,今取り組まれている暗号化方式は「単一換字式暗号」と呼ばれ,文字の出現頻度を分析する頻度分析によって簡単に破られるものであることと,そもそもそんな回りくどいことをしなくても鍵長が短すぎるのでコンピュータで破るに1秒も要さないことですかね...

何はともあれ,実装できているのは素晴らしいことと思います.

1Like

この暗号を実装したのですが、この暗号はどういった場面で応用されるのでしょうか?

先も申しましたとおり,本手法では鍵長が短すぎる上に単純な実装なので現代暗号の中ではお遊びの場面でしか使われません.映画「サマーウォーズ」の解説で同じようにやってみたパターンを示していました.この程度の鍵長であれば彼らのように人力で解読可能です.

鍵長を長くしてブロック暗号化方式に基づいた暗号化を行うのが一般的なので,まだ現実で応用はしないほうが良いでしょう.

0Like

Your answer might help someone💌