Advertisement
jukaukor

RSAPublicKeyGenerator.py

Aug 7th, 2019
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.91 KB | None | 0 0
  1. # Generoidaan kaksi suurta alkulukua p ja q
  2. # Näiden tulo n= p * q on toinen julkinen avain
  3. # Avain n määrittää viestin pituuden ylärajan
  4. # Jos viesti on muutettu numeroiksi, pituus on numeroiden määrä
  5. # Toiseksi julkiseksi avaimeksi eksponentti e = 65537
  6. # Alkuluvun testauksessa käytetään Miller-Rabinin menetelmää,
  7. # joka on virheetön lukua 341550071728321 pienemmille
  8. # ja sitä suuremmille virheen mahdollisuus äärimmäisen pieni
  9. # Suuria alkulukuja käytetään julkisen avaimen salauksessa
  10. # Alkulukujen generoinnissa käytetty lähdettä https://inventwithpython.com/hacking/chapter23.html
  11. # Selväkielinen viesti salataan julkisilla avaimilla n ja e
  12. # Salaus puretaan privaatilla purkuavaimella d - yhdessä julkisen avaimen n kanssa
  13. # Alla oleva ohjelma käyttää suositeltua eksponentti e = 65537 ja luo avaimen n
  14. # ja laskee näistä purkuavaimen d
  15.  
  16. # Juhani Kaukoranta 7.8.2019
  17.  
  18. import random
  19. import math
  20. import time
  21. import binascii
  22.  
  23. # *** Pääohjelman käyttämät funktiot ***
  24.  
  25. # alkuluvun generointi käyttäen annettua bittipituutta
  26. def generateLargePrime(keysize):
  27. # Return a random prime number of keysize bits in size.
  28. while True:
  29. num = random.randrange(2**(keysize-1), 2**(keysize))
  30. if is_prime(num):
  31. return num
  32.  
  33. # Miller-Rabin correct and probabilistic composite, prime test
  34. # correct answers for n less than 341550071728321
  35. # and then reverting to the probabilistic form
  36. # source https://rosettacode.org/wiki/Miller%E2%80%93Rabin_primality_test#Python
  37.  
  38. def _try_composite(a, d, n, s):
  39. if pow(a, d, n) == 1:
  40. return False
  41. for i in range(s):
  42. if pow(a, 2**i * d, n) == n-1:
  43. return False
  44. return True # n is definitely composite
  45.  
  46. def is_prime(n, _precision_for_huge_n=16):
  47. # _known_lowprimes are primes < 1000
  48.  
  49.  
  50. if n in _known_lowprimes:
  51. return True
  52. if any((n % p) == 0 for p in _known_lowprimes) or n in (0, 1):
  53. return False
  54. d, s = n - 1, 0
  55. while not d % 2:
  56. d, s = d >> 1, s + 1
  57. # Returns exact according to http://primes.utm.edu/prove/prove2_3.html
  58. if n < 1373653:
  59. return not any(_try_composite(a, d, n, s) for a in (2, 3))
  60. if n < 25326001:
  61. return not any(_try_composite(a, d, n, s) for a in (2, 3, 5))
  62. if n < 118670087467:
  63. if n == 3215031751:
  64. return False
  65. return not any(_try_composite(a, d, n, s) for a in (2, 3, 5, 7))
  66. if n < 2152302898747:
  67. return not any(_try_composite(a, d, n, s) for a in (2, 3, 5, 7, 11))
  68. if n < 3474749660383:
  69. return not any(_try_composite(a, d, n, s) for a in (2, 3, 5, 7, 11, 13))
  70. if n < 341550071728321:
  71. return not any(_try_composite(a, d, n, s) for a in (2, 3, 5, 7, 11, 13, 17))
  72. # otherwise
  73. return not any(_try_composite(a, d, n, s)
  74. for a in _known_lowprimes[:_precision_for_huge_n])
  75.  
  76. # lasketaan valmiiksi _known_lowprimes eli alkuluvut < 1000
  77. # nopeuttaa huomattavasti tarkistusta, onko luku alkuluku
  78. _known_lowprimes = [2, 3]
  79. _known_lowprimes += [x for x in range(5, 1000, 2) if is_prime(x)]
  80.  
  81. # extended euclidean algoritm
  82. # ax + by = gcd(a,b)
  83. # used in modular inverse modinv(a,m)
  84. def extended_gcd(aa, bb):
  85. lastremainder, remainder = abs(aa), abs(bb)
  86. x, lastx, y, lasty = 0, 1, 1, 0
  87. while remainder:
  88. lastremainder, (quotient, remainder) = remainder, divmod(lastremainder, remainder)
  89. x, lastx = lastx - quotient*x, x
  90. y, lasty = lasty - quotient*y, y
  91. return lastremainder, lastx * (-1 if aa < 0 else 1), lasty * (-1 if bb < 0 else 1)
  92.  
  93. # least common multiple, tarvitaan privaatin purkuavaimen d laskemiseen
  94. def lcm(x, y):
  95. return x*y // math.gcd(x,y)
  96.  
  97. # modular inverse tarvitaan privaatin purkuavaimen d laskemiseen
  98. def modinv(a, m):
  99. g, x, y = extended_gcd(a, m)
  100. if g != 1:
  101. raise ValueError
  102. return x % m
  103.  
  104. # ***pääohjelma***
  105. # Luodaan kaksi alkulukua p ja q. Suositeltu eksponentti e=65537 ei saa olla
  106. # luvun moduli = lcm(p-1,q-1) tekijänä
  107. e = 65537 # sertifioitu exponentti joka toimii toisena julkisena avaimena
  108. print("Ohjelma generoi kaksi bittimäärältään halutunkokoista alkulukua")
  109. print("Näistä saadun avaimen n bittimäärä on noin 2-kertainen")
  110. bittipituus = int(input("Haluttu bittimäärä, esim 256, 512,1024,2048 "))
  111. p = generateLargePrime(bittipituus)
  112. q = generateLargePrime(bittipituus)
  113. moduli = lcm(p-1,q-1)
  114. while moduli % e == 0: # moduli ei saa olla jaollinen e:llä
  115. p = generateLargePrime(bittipituus)
  116. q = generateLargePrime(bittipituus)
  117. moduli = lcm(p-1,q-1)
  118. print("Alkuluku p = ",p)
  119. print("Alkuluku q = ",q)
  120. print("Alkulukujen bittipituus = ",bittipituus)
  121. n = p * q # julkinen avain
  122. print(" Julkinen avain n = ",n)
  123. print("Julkisen avaimen n pituus = ",len(str(n))," numeroa")
  124. print ("Julkisen avaimen n bittipituus = ", math.log(n,2))
  125. print("Eksponentti e = ",e)
  126.  
  127. # Nyt meillä on eksponentti e ja laskettu kelvollinen n ja moduli
  128. # Lasketaan e:n ja modulin avulla salauksen privaatti purkuavain d
  129.  
  130. d = modinv(e,moduli)
  131. print("Salauksen privaatti purkuavain d = ",d)
  132. print(" ")
  133. print(" ****** viestin kirjoitus, salaus, purku selväkieliseksi *****")
  134. selko_text = input("Kirjoita selväkielinen teksti: ")
  135. hex_text = binascii.hexlify(selko_text.encode()) # selkoteksti heksadesimaalimuodossa, 2 hex/asciimerkki
  136. int_text = int(hex_text,16) # selkoteksti kokonaislukuna
  137. if int_text > n:
  138. raise Exception("teksti on liian pitkä avaimelle n, jaa teksti vaikka lyhyempiin pätkiin!")
  139. print("Selväkielinen teksti kokonaislukuna = ",int_text)
  140. crypt_text = pow(int_text,e,n) # salattu teksti
  141. print("salattu teksti = ",crypt_text)
  142. avattu_inttext = pow(crypt_text,d,n)
  143. print("Avattu teksti kokonaislukuna = ",avattu_inttext)
  144. avattu_selkotext = binascii.unhexlify(hex(avattu_inttext)[2:]).decode()
  145. print("Avattu teksti luettavassa muodossa = ",avattu_selkotext)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement