Python encryption program (ECC) - python

I'm trying to code an encryption program that will encode a user's Inputed - if that's a word - string. The encryption method is just a basic use of an elliptic curve encryption and I am currently working on the encryption part of the program at the moment before I work on the mathematical, inverse modules etc. Etc. Required for public and private key calculations. Currently I am using the key pub = 5 and a max value (derived from the product of 2 random primes) of 91. This is all the information needed and the word I am testing the encryption on is 'happy'.
So far here is the code.
word = 'happy'
pub = 5
m = 91
for i in range(pub):
if i == 0:
word = word
else:
word = output
for x in word:
a = [(((ord(z)*ord(z))+1)/m) for z in word]
b = [chr(i) for i in a]
c = [str(i) for i in b]
d = ''.join([str(i) for i in c])
output = d
What I am trying to do is encrypt each letter by multiplying the ASCII value it belongs too by itself and then use the chr() function to rejoin the string after a process of adding 1 then dividing by m , thus creating a new word. Then, using that new string, set it as the value of word for the next cycle in the loop, so the process continues until it has finished pub amount of times and encrypted the word. I'm having a lot of difficulties with this and I don't know where to start with explaining the issues. I'm relatively new to Python and any suggestions and/or advice on completing this fast would be very much appreciated. Thank you in advance.

First, check that your math is right. Your formula (z**2 + 1)/m grows quadratically. My understanding of crypto is quite limited, but it doesn't look right to me. It should be some kind of one-to-one mapping from input to output. But it maps several neighboring characters to the same output. Also, the results grow with every round.
You can only convert the integers back to ascii characters for a range up to 256. That's what your error message says. It's proably thrown in the second iteration of your outer for loop.
You probably need to get the value range down to 256 again.
I suppose you miss a crucial part off the algorithm you are trying to implement, maybe some modulo operation.
Also some minor python hints:
You can use the built in power operator **, so you don't have to evaluate ord() twice.
((ord(z) ** 2) + 1) / m
You can do the conversion back to the string in one step like this:
output = ''.join([str(chr(i)) for i in a])

Related

EntwicklerHeld Transposition Cipher

I'm trying to improve my coding skills on entwicklerheld.de
and right now I'm trying to solve the transposition cipher challenge:
We consider a cipher in which the plaintext is written downward and diagonally in successive columns. The number of rows or rails is given. When reaching the lowest rail, we traverse diagonally upwards, and after reaching the top rail, there is a change of direction again. Thus, the alphabets [sic] of the message are written in a zigzag pattern. After each alphabet is written, the individual lines are combined to obtain the cipher text.
Given is the plain text "coding" and the number of rails 2. The plain text is now arranged in a zigzag pattern as described above. The encoded text is obtained by combining the lines one after the other.
Thus, the encrypt() function should return the cipher "cdnoig".
The same procedure is used for entire sentences or texts as for individual words. The only thing to note here is that spaces also count as a single character.
Given is the plain text "rank the code" and the number of rails 2.
Your function should return the cipher "rn h oeaktecd".
This should work with other examples with 2 rails as well.
The encryption is very easy with a multi dimensional array.
My question
I'm stuck at the decryption part.
My idea is to build an array with 0 and 1 (to show were a character has to be). Then fill every array (line 1... line 2 ... line 3) with the characters in the order of the cipher text.
Then I iterate a third time over the array to read the word in zig-zag.
I don't know, but it feels very strange to iterate 3 times over the array. Maybe there is a zig-zag algorithm or so?
You could first define a generator that gives the mapping for each index to the index where the character has to be taken from during encryption. But this generator would not need to get the plain text input, just the length of it. As this generator just produces the indices, it can be used to decrypt as well.
It was not clear to me whether the question is only about the case where the number of rails is 2. With a bit of extra logic, this can be made for any greater number of rails also.
Here is how that could look:
# This generator can be used for encryption and decryption:
def permutation(size, numrails):
period = numrails * 2 - 2
yield from range(0, size, period) # top rail
# Following yield-from statement only needed when number of rails > 2
yield from (
index
for rail in range(1, numrails - 1)
for pair in zip(range(rail, size, period),
range(rail + period - rail*2, size + period, period))
for index in pair
if index < size
)
yield from range(numrails - 1, size, period) # bottom rail
def encrypt(plain, numrails):
n = len(plain)
return "".join([plain[i] for i in permutation(n, numrails)])
def decrypt(encrypted, numrails):
n = len(encrypted)
plain = [None] * n
for source, target in enumerate(permutation(n, numrails)):
plain[target] = encrypted[source]
return "".join(plain)

Improving the performance of a sliding-window fragment function in Python 3

I have a script in Python 3.6.8 which reads through a very large text file, where each line is an ASCII string drawn from the alphabet {a,b,c,d,e,f}.
For each line, I have a function which fragments the string using a sliding window of size k, and then increments a fragment counter dictionary fragment_dict by 1 for each fragment seen.
The same fragment_dict is used for the entire file, and it is initialized for all possible 5^k fragments mapping to zero.
I also ignore any fragment which has the character c in it. Note that c is uncommon, and most lines will not contain it at all.
def fragment_string(mystr, fragment_dict, k):
for i in range(len(mystr) - k + 1):
fragment = mystr[i:i+k]
if 'c' in fragment:
continue
fragment_dict[fragment] += 1
Because my file is so large, I would like to optimize the performance of the above function as much as possible. Could anyone provide any potential optimizations to make this function faster?
I'm worried I may be rate limited by the speed of Python loops, in which case I would need to consider dropping down into C/Cython.
Numpy may help in speeding up your code:
x = np.array([ord(c) - ord('a') for c in mystr])
filter = np.geomspace(1, 5**(k-1), k, dtype=int)
fragment_dict = collections.Counter(np.convolve(x, filter,mode='valid'))
The idea is, represent each k length segment is a k-digit 5-ary number. Then, converting a list of 0-5 integers equivalent to the string to its 5-ary representation is equivalent to applying a convolution with [1,5,25,125,...] as filter.

Add a number to each element/integer in an array

I am creating a very simple encryption algorithm where I covert each letter of a word into ascii, placing the ascii values into an array and then adding a number onto each value. To then convert the ascii back to letters, which will then output the new encrypted word. Known as the ceaser cipher.
But I cannot figure out how to add the key number to each element of the array.
As others will mention, when posing a question like this, please post a code attempt first. Having clear input/output and any associated stack trace errors helps people answer your question better.
That being said, I've written a simple ceaser cipher encryption method that shifts to the right based on a given key. This works by converting the characters of a string to their numerical ascii representations using the built in method ord(). We then add the shift value to this representation to right shift the values over by a given amount. Then covert back to characters using chr() We take into account some wrapping back to the beginning of the alphabet if the shifted_value exceeds that of 'z'.
def ceaser_cipher_encryption(string, shift):
alpha_limit = 26
encrypted_msg = []
for index, character in enumerate(string.lower()):
isUpperCharacter = string[index].isupper()
shifted_value = ord(character) + shift
if shifted_value > ord('z'):
encrypted_msg.append(chr(shifted_value - alpha_limit))
else:
encrypted_msg.append(chr(shifted_value))
if isUpperCharacter:
encrypted_msg[index] = encrypted_msg[index].upper()
return ''.join(encrypted_msg)
Sample Output:
>>> ceaser_cipher_encryption("HelloWorld", 5)
MjqqtBtwqi
Try having a look online for solutions:
Caesar Cipher Function in Python
https://inventwithpython.com/chapter14.html
These links will provide you with clear answers to your questions.

Assistance with a PseudoRandom Function?

I'm currently working on an encryption project, and I correctly implemented a Caesarian function in my program, but I need to implement another encryption method.
Instructions: We will use a modified version called Pseudo-random offset. We won’t need to pre-distribute a booket, just a password, and those are shorter and don’t need to be written down. The password is then used to seed the python random number generator, as described above. You should start with the Caesarian code, but instead of creating one offset at the beginning of the function, create a new one for every single character.
Below is my Code for the Caesarian. Can anyone provide an example for maybe one character in the code so I can kind of follow along with what's going on? I'm new to python and am still learning.
def Caesarian(fin, fout, encrypt_or_decrypt_choice, alphabet):
# Determine the offset by generating a random number in the correct range.
# This will be the same random number, if the password sent to random.seed is the same.
offset = random.randrange(1,len(alphabet))
if encrypt_or_decrypt_choice=='d':
offset = -offset
print "Using the secret offset of", offset
# Read every line of the input file.
for line1 in fin:
# Alter each character of the line1, putting the result into line2.
line2 = ""
for c in line1:
if c in alphabet:
pos1 = alphabet.find(c)
pos2 = (pos1+offset)%len(alphabet)
line2 += alphabet[pos2]
# Write each resulting line2 to the output file.
fout.write(line2)
In the Ceaser cipher, you shift each character by a constant, fixed amount.
The Vigenère cipher is an improvement upon that, by shifting each letter within a small group by a fixed amount. For example, a key of 123 could mean to "shift by one, then by two, then by three, and then repeat", so the message "aaaaaa" would be encrypted as "bcdbcd".
The Vigenère cipher shares a weakness with the Ceaser cipher - it's possible to do calculate the statistics for which letter patterns are most common, and use them to optimize a brute-force search for the key.
What you're building is slightly more complex - a simple stream cipher. The goal here is to encrypt each character by a different amount - so it's almost a one-time pad, but without the overhead of transferring an extremely large key.
Now take a look at Python's random module:
>>> import random
>>> random.choice(range(100))
42
>>> random.choice(range(100))
46
>>> random.choice(range(100))
92
As you see, each value is different. If we were to re-run Python, we would get a different series of numbers. If the numbers were truly random, they would be useless for this method of encryption, as the receiver wouldn't be able to recreate the same stream.
Seeding the pseudo-random number generator allows us to fix the initial state so that the results are predictable:
>>> random.seed(5)
>>> random.choice(range(100))
62
>>> random.choice(range(100))
74
And now if I re-seed it, we'll get the same exact numbers:
>>> random.seed(5)
>>> random.choice(range(100))
62
>>> random.choice(range(100))
74
To migrate your original code, you need to change your initial calculation of the offset to setting the seed, and then update the offset for each character.
(Here's my attempt at updating the pasted code):
def streamCipher(fin, fout, encrypt_or_decrypt_choice, alphabet, seed):
# Seed random with the shared secret
random.seed(seed)
# Read every line of the input file.
for line1 in fin:
# Alter each character of the line1, putting the result into line2.
line2 = ""
for c in line1:
if c in alphabet:
# Determine the offset by generating a random number in the correct range.
# This will return the same sequence of random numbers, if the seed is the same.
offset = random.randrange(1,len(alphabet))
if encrypt_or_decrypt_choice=='d':
offset = -offset
pos1 = alphabet.find(c)
pos2 = (pos1+offset)%len(alphabet)
line2 += alphabet[pos2]
# Write each resulting line2 to the output file.
fout.write(line2)

python parallel computing: split keyspace to give each node a range to work on

My question is rather complicated for me to explain, as i'm not really good at maths, but i'll try to be as clear as possible.
I'm trying to code a cluster in python, which will generate words given a charset (i.e. with lowercase: aaaa, aaab, aaac, ..., zzzz) and make various operations on them.
I'm searching how to calculate, given the charset and the number of nodes, what range each node should work on (i.e.: node1: aaaa-azzz, node2: baaa-czzz, node3: daaa-ezzz, ...). Is it possible to make an algorithm that could compute this, and if it is, how could i implement this in python?
I really don't know how to do that, so any help would be much appreciated
Any way that you could compute a small integer from the string would be fine for clustering. For example, compute a hash with md5, and look at a byte of it:
import hashlib
s = "aaac"
num_nodes = 5 # or whatever
m = hashlib.md5(s)
node = ord(m.digest()[0]) % num_nodes
print node # prints 2
This won't guarantee to evenly distribute all the strings, but it will be close.
You should be able to treat your words as numerals in a strange base. For example, let's say you have a..z as your charset (26 characters), 4 character strings, and you want to distribute among equally 10 machines. Then there are a total of 26^4 strings, so each machine gets 26^4/10 strings. The first machine will get strings 0 through 26^4/10, the next 26^4/10 through 26^4/5, etc.
To convert the numbers to strings, just write the number in base 26 using your charset as the numbers. So 0 is 'aaaa' and 26^4/10 = 2*26^3 + 15*26^2 + 15*26 +15 is 'cppp'.

Categories