Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 159 lines (124 sloc) 6.55 kb
f16b361 Al Sweigart Initial commit.
authored
1 # RSA Cipher
2 # http://inventwithpython.com/codebreaker (BSD Licensed)
3
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
4 import sys
5
6 # IMPORTANT: The block size MUST be less or equal than the key size!
7 # (Note: The block size is in bytes, the key size is in bits. There are 8 bits in 1 byte.)
8 DEFAULT_BLOCK_SIZE = 128
9 BYTE_SIZE = 256 # One byte has 256 different values.
10
f16b361 Al Sweigart Initial commit.
authored
11 def main():
12 # Runs a test that encrypts a message to a file or decrypts a message
13 # from a file.
14 filename = 'encrypted_file.txt'
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
15 mode = 'encrypt' # set to 'encrypt' or 'decrypt'
f16b361 Al Sweigart Initial commit.
authored
16
17 if mode == 'encrypt':
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
18 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'''
f16b361 Al Sweigart Initial commit.
authored
19 privKeyFilename = 'al_sweigart_privkey.txt'
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
20 print('Encrypting and writing to %s...' % (filename))
21 encryptedText = encryptAndWriteToFile(filename, privKeyFilename, message, 128)
f16b361 Al Sweigart Initial commit.
authored
22
23 print('Encrypted text:')
24 print(encryptedText)
25
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
26 if mode == 'decrypt':
f16b361 Al Sweigart Initial commit.
authored
27 pubKeyFilename = 'al_sweigart_pubkey.txt'
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
28 print('Reading from %s and decrypting...' % (filename))
f16b361 Al Sweigart Initial commit.
authored
29 decryptedText = readFromFileAndDecrypt(filename, pubKeyFilename)
30
31 print('Decrypted text:')
32 print(decryptedText)
33
34
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
35 def getBlocksFromText(message, blockSize=DEFAULT_BLOCK_SIZE):
f16b361 Al Sweigart Initial commit.
authored
36 # Converts a string message to a list of block integers. Each integer
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
37 # represents 512 (or whatever blockSize is set to) string characters.
f16b361 Al Sweigart Initial commit.
authored
38
39 messageBytes = message.encode('ascii') # convert the string to bytes
40 blockInts = []
41 for blockStart in range(0, len(messageBytes), blockSize):
42 # Calculate the block integer for this block of text
43 blockInt = 0
44 for i in range(blockStart, min(blockStart + blockSize, len(messageBytes))):
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
45 blockInt += int(messageBytes[i]) * (BYTE_SIZE ** (i % blockSize))
f16b361 Al Sweigart Initial commit.
authored
46 blockInts.append(blockInt)
47 return blockInts
48
49
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
50 def getTextFromBlocks(blockInts, messageLength, blockSize=DEFAULT_BLOCK_SIZE):
f16b361 Al Sweigart Initial commit.
authored
51 # Converts a list of block integers to the original message string. The
52 # original message length is needed to properly convert the last block
53 # integer.
54 message = []
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
55
f16b361 Al Sweigart Initial commit.
authored
56 for blockInt in blockInts:
57 blockMessage = []
58 for i in range(blockSize-1, -1, -1):
c4fd6ab Al Sweigart Pylint-suggested fixes.
authored
59 if len(message) + i < messageLength:
60 # Decode the message string for the 512 (or whatever blockSize is
61 # set to) characters from this block integer.
62 charNumber = blockInt // (BYTE_SIZE ** i)
63 blockInt = blockInt % (BYTE_SIZE ** i)
64 blockMessage.insert(0, bytes([charNumber]).decode('ascii'))
f16b361 Al Sweigart Initial commit.
authored
65 message.extend(blockMessage)
66 return ''.join(message)
67
68
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
69 def encryptMessage(message, key, blockSize=DEFAULT_BLOCK_SIZE):
f16b361 Al Sweigart Initial commit.
authored
70 # Converts the message string into a list of block integers, and then
71 # encrypt each block integer. Be sure to pass the PUBLIC key to encrypt.
72 encryptedBlocks = []
73 n, e = key
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
74
75 for block in getBlocksFromText(message, blockSize):
f16b361 Al Sweigart Initial commit.
authored
76 # ciphertext = plaintext ^ e mod n
77 encryptedBlocks.append(pow(block, e, n))
78 return encryptedBlocks
79
80
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
81 def decryptMessage(encryptedBlocks, messageLength, key, blockSize=DEFAULT_BLOCK_SIZE):
f16b361 Al Sweigart Initial commit.
authored
82 # Decrypts a list of encrypted block ints into the original message
83 # string. The original message length is required to properly decrypt
84 # the last block. Be sure to pass the PRIVATE key to decrypt.
85 decryptedBlocks = []
86 n, d = key
87 for block in encryptedBlocks:
88 # plaintext = ciphertext ^ d mod n
89 decryptedBlocks.append(pow(block, d, n))
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
90 return getTextFromBlocks(decryptedBlocks, messageLength, blockSize)
f16b361 Al Sweigart Initial commit.
authored
91
92
93 def readKeyFile(keyFilename):
94 # Given the filename of a file that contains a public or private key,
95 # return the key as a (n,e) or (n,d) tuple value.
96 fp = open(keyFilename)
97 content = fp.read()
98 fp.close()
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
99 keySize, N, EorD = content.split(',')
100 return (int(keySize), int(N), int(EorD))
f16b361 Al Sweigart Initial commit.
authored
101
102
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
103 def encryptAndWriteToFile(messageFilename, keyFilename, message, blockSize=DEFAULT_BLOCK_SIZE):
f16b361 Al Sweigart Initial commit.
authored
104 # Using a key from a key file, encrypt the message and save it to a
105 # file. Returns the encrypted message string.
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
106 keySize, N, EorD = readKeyFile(keyFilename)
107
108 # Check that key size is greater than block size.
109 if keySize < blockSize * 8: # * 8 to convert bytes to bits
110 sys.exit('ERROR: Block size is %s and key size is %s. The RSA cipher requires the block size to be less than the key size. Either decrease the block size or use different keys.' % (blockSize, keySize))
111 key = (N, EorD)
f16b361 Al Sweigart Initial commit.
authored
112
113 # Encrypt the message
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
114 encryptedBlocks = encryptMessage(message, key, blockSize)
f16b361 Al Sweigart Initial commit.
authored
115
116 # Convert the large int values to one string value.
117 for i in range(len(encryptedBlocks)):
118 encryptedBlocks[i] = str(encryptedBlocks[i])
119 encryptedContent = ','.join(encryptedBlocks)
120
121 # Write out the encrypted string to the output file.
122 fp = open(messageFilename, 'w')
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
123 fp.write('%s_%s_%s' % (len(message), blockSize, encryptedContent))
f16b361 Al Sweigart Initial commit.
authored
124 fp.close()
125
126 # Also return the encrypted string.
127 return encryptedContent
128
129
130 def readFromFileAndDecrypt(messageFilename, keyFilename):
131 # Using a key from a key file, read an encrypted message from a file
132 # and then decrypt it. Returns the decrypted message string.
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
133 keySize, N, EorD = readKeyFile(keyFilename)
134 key = (N, EorD)
f16b361 Al Sweigart Initial commit.
authored
135
136 # Read in the message length and the encrypted message from the file.
137 fp = open(messageFilename)
138 content = fp.read()
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
139 messageLength, blockSize, message = content.split('_')
140 messageLength = int(messageLength)
141 blockSize = int(blockSize)
142
143 # Check that key size is greater than block size.
144 if keySize < blockSize * 8: # * 8 to convert bytes to bits
145 sys.exit('ERROR: Block size is %s and key size is %s. The RSA cipher requires the block size to be less than the key size. Did you specify the correct key file and encrypted file?' % (blockSize, keySize))
f16b361 Al Sweigart Initial commit.
authored
146
147 # Convert the encrypted message into large int values.
148 encryptedBlocks = []
149 for block in message.split(','):
150 encryptedBlocks.append(int(block))
151
152 # Decrypt the large int values.
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
153 return decryptMessage(encryptedBlocks, messageLength, key, blockSize)
f16b361 Al Sweigart Initial commit.
authored
154
155
91f8abb Al Sweigart First round of personal fixes. This is an unhelpful log message.
authored
156 # If rsaCipher.py is run (instead of imported as a module) call
157 # the main() function.
f16b361 Al Sweigart Initial commit.
authored
158 if __name__ == '__main__':
159 main()
Something went wrong with that request. Please try again.