Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1790587
  • 博文数量: 297
  • 博客积分: 285
  • 博客等级: 二等列兵
  • 技术积分: 3006
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-06 22:04
个人简介

Linuxer, ex IBMer. GNU https://hmchzb19.github.io/

文章分类

全部博文(297)

文章存档

2020年(11)

2019年(15)

2018年(43)

2017年(79)

2016年(79)

2015年(58)

2014年(1)

2013年(8)

2012年(3)

分类: Python/Ruby

2017-05-21 13:18:16

我总是说,要了解RSA,首先你应该有两个很大的质数. 

Generating Public and Private Keys
A key in the RSA scheme is made of two numbers. There are three steps to creating the
keys:
1. Create two random, very large prime numbers. These numbers will be called p and q.
Multiply these numbers to get a number which we will call n.
2. Create a random number, called e, which is relatively prime with (p – 1) × (q – 1).
3. Calculate the modular inverse of e. This number will be called d.
The public key will be the two numbers n and e. The private key will be the two numbers
n and d. (Notice that both keys have the number n in them.) We will cover how to encrypt
and decrypt with these numbers when the RSA cipher program is explained. First let’s
write a program to generate these keys.

点击(此处)折叠或打开

  1. import random
  2. import sys
  3. import os
  4. import rabinMiller
  5. import cryptMath

  6. def main():
  7.     #create a public/private keypair with 1024 bit keys
  8.     print("Making key files...")
  9.     makeKeyFiles("al_sweigart", 1024)
  10.     print("Key files made")


  11. def generateKey(keySize):
  12.     #create a public/private key pair with keys that are keySize bits in
  13.     #size, This function may take a while to run.

  14.     #step 1: create two primes number, p and q , Calculate n = p * q
  15.     print("Generating a prime...")
  16.     p = rabinMiller.generateLargePrime(keySize)
  17.     print("Generating q prime...")
  18.     q = rabinMiller.generateLargePrime(keySize)
  19.     n = p * q

  20.     #step 2: create a number e that is relatively prime to (p-1)*(q-1)
  21.     print("Generating e that is relatively prime to (p-1)*(q-1)...")
  22.     while True:
  23.         #keep trying random number for e untile one is valid
  24.         e = random.randrange(2 ** (keySize-1), 2**(keySize))

  25.         if cryptMath.gcd(e, (p-1)*(q-1)) == 1:
  26.             break

  27.     #step 3, Calculate d, the mod inverse of e
  28.     print("Calculating d that is mod inverse of e...")

  29.     d = cryptMath.findModInverse(e, (p-1)*(q-1))

  30.     publicKey=(n, e)
  31.     privateKey = (n, d)

  32.     print("Pubic key:", publicKey)
  33.     print("Private key:", privateKey)

  34.     return (publicKey, privateKey)

  35. def makeKeyFiles(name, keySize):
  36.     #create two files "x_pubkey.txt" and "x_privkey.txt"
  37.     #where x is the value in name) with the n,e and d,e
  38.     #integers written in them. delimited by a comma
  39.     
  40.     #our safety check will prevent us from overwriting our old key file
  41.     if os.path.exists("{}_pubkey.txt".format(name)) or \
  42.         os.path.exists("{}_privkey.txt".format(name)) :

  43.         sys.exit("Warning: The file {}_pubkey.txt or {}_privkey.txt already exists! use a different name or delete\
  44.             these files and re-run this program. ".format(name, name))

  45.     publicKey, privateKey = generateKey(keySize)

  46.     print()
  47.     print("The public key is {} and a {} digit number".format(len(str(publicKey[0])), len(str(publicKey[1]))))

  48.     print("Writing public key to file {}_pubkeytxt".format(name))

  49.     fo = open("{}_pubkey.txt".format(name), "w")
  50.     fo.write("{},{},{}".format(keySize, publicKey[0],publicKey[1]))

  51.     fo.close()
  52.     print()
  53.         
  54.     print("The private key is a {} and a {} digit number.".format(len(str(privateKey[0])), len(str(privateKey[1]))))
  55.     print("writing privae key to file {}_privkey.txt".format(name))
  56.     fo = open("{}_privkey.txt".format(name), "w")
  57.     fo.write("{},{},{}".format(keySize, privateKey[0],privateKey[1]))

  58.     fo.close()



  59. if __name__== "__main__":
  60.     main()


其中import的rabinMiller.py是rabinMiller算法来找到一个很大的质数.


点击(此处)折叠或打开

  1. import random

  2. def rabinMiller(num):
  3.     #returns True if num is a prime number

  4.     s = num -1
  5.     t =0
  6.     while s % 2 ==0:
  7.         #keep halving s while it is even(and use t
  8.         #to count how many times we halve s)

  9.         s = s // 2
  10.         t += 1


  11.     for trials in range(5): #try to falsify num primality 5 times
  12.         a = random.randrange(2, num -1)
  13.         v = pow(a,s,num)

  14.         if v != 1: #this test does not apply if v is 1
  15.             i=0
  16.             while v != (num -1):
  17.                 if i==t -1:
  18.                     return False
  19.                 else:
  20.                     i += 1
  21.                     v = (v**2) % num
  22.     return True

  23. def isPrime(num):
  24.     #Return true if num is a prime number, This function does a quicker
  25.     #prime number check before calling rabinMiller()

  26.     if (num < 2):
  27.         return False #0,1 and negative numbers are not prime

  28.     # About 1/3 of the time we can quickly determine if num is not prime
  29.     # by dividing by the first few dozen prime numbers. This is quicker
  30.     # than rabinMiller(), but unlike rabinMiller() is not guaranteed to
  31.     # prove that a number is prime.
  32.     lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

  33.     if num in lowPrimes:
  34.         return True

  35.     #see if any of the low prime numbers can divide num
  36.     for prime in lowPrimes:
  37.         if (num % prime == 0):
  38.             return False

  39.     #if all else fails, call rabinMaller() to determine if num is a prime
  40.     return rabinMiller(num)


  41. def generateLargePrime(keysize = 1024):
  42.     
  43.     #return a random prime number of keysize bits in size
  44.     while True:
  45.         num = random.randrange(2**(keysize-1), 2**(keysize))
  46.         if isPrime(num):
  47.             return num


最后就是使用生成的key来encrypt/decrypt 一些text 然后写入文件或者读取出来.

点击(此处)折叠或打开

  1. import sys

  2. #IMPORTANT: The block size MUST be less than or equal to the key
  3. ##(Note: The block size is in bytes, the key size is in bits, There
  4. #are 8 bits in 1 byte . )

  5. DEFAULT_BLOCK_SIZE = 128 #bytes
  6. BYTE_SIZE = 256 #one byte has 256 different values

  7. def main():
  8.     
  9.     #Run a test that encrypts a message to a file or decrypts a message from a file
  10.     filename = "encrypted_file.txt" #The file to write to /read from
  11.     mode = "decrypt" #set to encrypt or decrypt

  12.     if mode == "encrypt":
  13.         message = '''"Journalists belong in the gutter because that is where the ruling classes throw their guilty secrets." -Gerald Priestland "The Founding Fathers gave the free press the protection it must have to bare the secrets of government and inform the people." -Hugo Black'''
  14.         publicKeyFileName = "al_sweigart_pubkey.txt"
  15.         print("Encrypting and writing to {}".format(filename))
  16.         encryptedText = encryptAndWriteToFile(filename, publicKeyFileName, message)

  17.         print("Encrypted text:")
  18.         print(encryptedText)

  19.     elif mode == "decrypt":
  20.         privKeyFileName = "al_sweigart_privkey.txt"
  21.         print("Reading from {} and decrypting ".format(filename))
  22.         decryptedText = readFromFileAndDecrypt(filename, privKeyFileName)

  23.         print("Decrypted text:")
  24.         print(decryptedText)

  25. def getBlocksFromText(message, blockSize = DEFAULT_BLOCK_SIZE):
  26.     #convert a string message to a list of block integers, Each integer
  27.     #represents 128 ( or whatever blocksize is set to )string characters.
  28.     messageBytes = message.encode("ascii") #convert the string to bytes

  29.     blockInts = []

  30.     for blockStart in range(0, len(messageBytes), blockSize):
  31.         #calculate the block integer for this block of text
  32.         blockInt = 0
  33.         for i in range(blockStart, min(blockStart + blockSize, len(messageBytes))):
  34.             blockInt += messageBytes[i] * (BYTE_SIZE ** (i % blockSize))

  35.         blockInts.append(blockInt)

  36.     return blockInts


  37. def getTextFromBlocks(blockInts, messageLength, blockSize=DEFAULT_BLOCK_SIZE):
  38.     #convert a list of block integers to the original message string
  39.     #The original message length is needed to properly convert the last block integer
  40.     message = []
  41.     for blockInt in blockInts:
  42.         blockMessage = []
  43.         for i in range(blockSize -1 , -1 , -1):
  44.             if len(message) + i < messageLength:
  45.                 #Decode the message string for the 128 (or whatever
  46.                 #blocksize is set to ) characters from this block integer
  47.                 asciiNumber = blockInt // (BYTE_SIZE ** i)
  48.                 blockInt = blockInt % (BYTE_SIZE ** i)
  49.                 blockMessage.insert(0, chr(asciiNumber))
  50.         
  51.         message.extend(blockMessage)
  52.     return "".join(message)


  53. def encryptMessage(message, key, blockSize = DEFAULT_BLOCK_SIZE):
  54.     #convert the message string into a list of block integers, and then
  55.     #encrypt each block integer. Pass the PUBLIC key to encrypt
  56.     encryptedBlocks = []
  57.     n , e = key

  58.     for block in getBlocksFromText(message, blockSize):
  59.         #ciphertext = plaintext ^ e mod n
  60.         encryptedBlocks.append(pow(block, e, n))

  61.     return encryptedBlocks


  62. def decryptMessage(encryptedBlocks, messageLength, key, blockSize = DEFAULT_BLOCK_SIZE):
  63.     #Decrypt a list of encrypted block ints into the orginal message String
  64.     #The original message length is required to properly decrypt
  65.     #The last block, Be sure to pass the PRIVATE key to decrypt
  66.     decryptedBlocks = []
  67.     n, d = key
  68.     for block in encryptedBlocks:
  69.         #plainText = cipher ^ d mode n
  70.         decryptedBlocks.append(pow(block , d, n ))

  71.     return getTextFromBlocks(decryptedBlocks, messageLength, blockSize)

  72. def readKeyFile(keyFileName):
  73.     #given the filename of a file that contains a public or private key,
  74.     #return the key as a (n, e) or (n, d) tuple value
  75.     fo = open(keyFileName)
  76.     content = fo.read()
  77.     fo.close()

  78.     keySize, n, EorD = content.split(",")
  79.     return (int(keySize),int(n), int(EorD))


  80. def encryptAndWriteToFile(messageFilename, keyFilename, message, blockSize=DEFAULT_BLOCK_SIZE):
  81.     #Using a key from a key file, encrypt the message and save it to a file
  82.     #Returns the encrypted message string
  83.     keySize, n, e = readKeyFile(keyFilename)

  84.     #check the key size is greater than block size
  85.     if keySize < blockSize * 8: # *8 to convert bytes to bits
  86.         sys.exit("ERROR: Block size is {} bits and key size is {} bits. The RSA\
  87.         cipher requires the block size to be equal to or less than the key size\
  88.         Either increase the block size or use different keys.".format(blockSize * 8, keySize))

  89.     #encrypt the message
  90.     encryptedBlocks = encryptMessage(message, (n , e), blockSize)

  91.     #convert the large int value to one string value
  92.     for i in range(len(encryptedBlocks)):
  93.         encryptedBlocks[i] = str(encryptedBlocks[i])
  94.     encryptedContent = ','.join(encryptedBlocks)

  95.     
  96.     #write out the encrypted string to the output file
  97.     encryptedContent = "{}_{}_{}".format(len(message), blockSize, encryptedContent)

  98.     fo = open(messageFilename, "w")
  99.     fo.write(encryptedContent)
  100.     fo.close()
  101.     #Also return the encrypted string
  102.     return encryptedContent


  103. def readFromFileAndDecrypt(messageFilename, keyFilename):
  104.     #using a key from a key file, read an encrypted message from a file
  105.     #and then decrypt it, returns the decrypted message string
  106.     keySize , n , d = readKeyFile(keyFilename)

  107.     #Read in the message length and the encrypted message from the file
  108.     fo = open(messageFilename)
  109.     content = fo.read()
  110.     messageLength,blockSize, encryptedMessage = content.split("_")
  111.     messageLength = int(messageLength)
  112.     blockSize = int(blockSize)

  113.     #check the key size is greater than block size
  114.     if keySize < blockSize * 8:
  115.         sys.exit("ERROR: Block size is {} bits and key size is {} bits. The RSA\
  116.         cipher requires the block size to be equal to or less than the key size\
  117.         .Either increase the block size or use different keys.".format(blockSize * 8, keySize))
  118.     
  119.     #convert the encrypted message into large int values
  120.     encryptedBlocks = []
  121.     for block in encryptedMessage.split(','):
  122.         encryptedBlocks.append(int(block))

  123.     #decrypt the large int values
  124.     return decryptMessage(encryptedBlocks, messageLength, (n, d), blockSize)

  125. #main() function
  126. if __name__=="__main__":
  127.     main()

阅读(1076) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~