So I am trying to find the key of one time-pad and I have 10 ciphertexts.(the plaintext letters are encoded as 8-bit ASCII
and the given ciphertexts are written in hex; and I'm using python 2.7)
the idea is that when you xor a character with a space the character gets uppercase or lowercase, and when you xor x with x it returns zero so when I xor two character of to ciphertexts I xor the key with the key and the message character with the message character.
so I wrote this code for xoring two hex.
def hex_to_text(s):
string=binascii.unhexlify(s)
return string
def XoR (a,b):
a="0x"+a
b="0x"+b
xor=chr(int(a,16) ^ int(b,16))
return hex_to_text(xor[2:])
when the key is an even number it the xor function works correct but when the key is odd it does not return the same character uppercase or lowercase.
what am i doing wrong?
a general idea on how to solve this, disregarding python:
lets start with saying a char is 8 bit ascii
if you look at the first char form the first ciphertext, you will probably notice that it is outside of the ascii values for plain text which one could say are a-z 0x61-0x7a A-Z 0x41-0x5a
there is a high probability that you only have to take values into account that, xored with this char, make it something inside the specified value ranges
the same holds for the other 9 texts and their respective first char
and, interestingly, the list of possible key values for this char has to hold for every ciphertext with the same key, so each and every ciphertext we look at reduces the range further
now, what can you do with this approach?
write a function that takes 2 parameters (bytes) and tests if the result of a xor falls into the specified range, if yes, return 1, if no return 0
now make 3 nested loops to call this function
outer loop (X) goes through the char positions in the ciphertext
middle loop (Y) goes from 0 to 255
inner loop (Z) goes through the ciphertexts
in the inner loop call your function with parameter 1 being the X character of your Z ciphertext and parameter 2 being Y
now what to do with the result:
you want to have a dictionary/lookup table that per position X holds an array of 255 elements
the index on these elements will be Y
the value for these elements will be the sum of your function results for all Z
in the end what you will have is for every position in your ciphertext, an array that tells you for each keybyte how likely it is the key ... the higher the value the higher the probability of being the key byte
then for each position in your ciphertext order the possible keybytes by their probability and partition them by probability
then take a chunk of all ciphertexts, lets say the first 8 to 16 chars, and calculate the plaintext for all keys in the highest probability group
store key chunk and plaintext chunk together in a list
now test your list of possible plaintexts against a common dictionary, and again rate them 1 if they contain words that can be found in a dictionary and 0 otherwise ... sum up for all different ciphertexts ... (or use another metric to rate how good a key is)
order the key chunks by the highest value (read: the key that potentialy solved the most chunks across all ciphertexts comes first and the one that produced garbage comes last) and continue with the next chunk ...
repeat this with bigger chunks, selecting not keybytes but the next smaller size of key chunks, until your chunksize gets to the ciphertext size...
of course this is an automated way to find a likely key, and there is some implementation work until you have a completely automated solution. if you just want to solve this 10 ciphertexts, you can abort the approach after the likely keybytes or the first chunks, and do the rest by hand ...
Related
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)
I have some data that has unique IDs stored as a string in the form:
ddd.dddddaddd.dddddz
Where d is some digit and a/z is some alphabet character. The digits may be 0-9 and the characters are either E or W for the a and N or S for the z.
I'd like to turn this into a unique integer and what I've tried using the hashlib module returns:
>>> int(hashlib.sha256(str.encode(s)).hexdigest(), 16)
Output: a very long integer (on another system cannot copy it)
Is there a way to generate a unique integer ID from a string so that it does not exceed 12 digits? I know that I will never need a unique integer ID beyond 12 digits.
Just something simple:
>>> s = '123.45678W123.45678S'
>>> int(s.translate(str.maketrans('EWNS', '1234', '.')))
123456782123456784
Not the impossible 12 digits you're still asking for in the question, but under the 20 digits you allowed in the comments.
As you are dealing with coordinates, I would try my best to keep the information in the final 12-digit ID.
If your points are global, it might be necessary to keep the degrees but they may be widespread, so you can sacrifice some information when it comes to precision.
If your points are local (all within a range of less than 10 degrees) you might skip the first two digits of the degrees and focus on the decimals.
As it may be possible that two points are close to each other, it may be prudent to reserve one digit as a serial number.
Proposal for widespread points:
s = "123.45678N123.45678E"
ident = "".join([s[0:6],s[10:16]]).replace(".","")
q = 0
if s[9]=="N":
q+=1
if s[-1]=="E":
q+=2
ident+=str(q)+'0'
The example would translate to 123451234530.
After computing the initial ident numbers for each ID, you should loop through them and increment the last digit if an ident is already taken.
This way you could easily reconstruct the location from the ID by just separating the first 10 digits to two degrees of the format ddd.dd and use the [-2] digit as an indicator of the quadrant (0:SW, 1:SE, 2:NW, 3:NE).
I need to create all combinations of these characters:
'0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM. '
That are 100 letters long, such as:
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'
I'm currently using this code:
import itertools
babel = itertools.product(k_c, repeat = 100)
This code works, but I need to be able to return the combination at a certain index, however itertools.product does not support indexing, turning the product into a list yields a MemoryError, and iterating through the product until I reaches a certain value takes too long for values over a billion.
Thanks for any help
With 64 characters and 100 letters there will be 64^100 combinations. For each value of the first letter, there will be 64^99 combinations of the remaining letters, then 64^98, 64^97, and so on.
This means that your Nth combination can be expressed as N in base 64 where each "digit" represents the index of the letter in the string.
An easy solution would be to build the string recursively by progressively determining the index of each position and getting the rest of the string with the remainder of N:
chars = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM. '
def comboNumber(n,size=100):
if size == 1: return chars[n]
return comboNumber(n//len(chars),size-1)+chars[n%len(chars)]
output:
c = comboNumber(123456789000000000000000000000000000000000000123456789)
print(c)
# 000000000000000000000000000000000000000000000000000000000000000000000059.90jDxZuy6drpQdWATyZ8007dNJs
c = comboNumber(1083232247617211325080159061900470944719547986644358934)
print(c)
# 0000000000000000000000000000000000000000000000000000000000000000000000Python.Person says Hello World
Conversely, if you want to know at which combination index a particular string is located, you can compute the base64 value by combining the character index (digit) at each position:
s = "Python.Person says Hello World" # leading zeroes are implied
i = 0
for c in s:
i = i*len(chars)+chars.index(c)
print(i) # 1083232247617211325080159061900470944719547986644358934
You are now this much closer to understanding base64 encoding which is the same thing applied to 24bit numbers coded over 4 characters (i.e 3 binary bytes --> 4 alphanumeric characters) or any variant thereof
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])
I'm trying to convert this Python code to C. But for the life of me, I can't figure out what this line here does. The rest of the program seems simple.
self.payload = "\x02\x00%s%s" % (
pack(">b", length),
"".join(random.choice(string.printable) for i in range(length)))
If anybody could give me a rough idea of what this is doing, it'd be much appreciated!
First line:
The correct translation of length = random.randint(18, 20) is int length = rand() % 3 + 18.
Now let's dissect the dense second line piece by piece.
"\x02\x00%s%s" % (x, y) means to substitute the format string with the given arguments (like sprintf()). In this case it means concatenating the bytes 0x02, 0x00 with two strings x and y to follow.
x = pack(">b", length) uses struct.pack(). In this case, it means to convert the integer value length into one byte representing its value. It's almost equivalent to using chr().
y = "".join(z) means to take each element in the list z (which must be a string) and concatenate them with "" (nothing) between them. (For example, "#".join(["a","b","c"]) --> "a#b#c".)
z = (random.choice(string.printable) for i in range(length)) returns a generator object. You can think of it as a list whose elements are computed on demand. In this case, it generates length elements where each element is one character randomly chosen from the string string.printable.
All in all, the second line yields a string that starts wxth 0x02 0x00, followed by (char)length, followed by length random characters each uniformly chosen from the set of chars string.printable.