I have a problem in this code.
Why it skips the last character of my string. Lets say I want to calculate a hash for "timeGetTime", the loop stops at 'e' character.
I tried to print the API name and it prints all characters correctly.
Edit:
correct hash is 0xFF407C2F but the output is 0xE07FFA03
def ROR(data, shift, size=32):
shift %= size
body = data >> shift
remains = (data << (size - shift)) - (body << size)
return (body + remains)
def calculateHash(apiName):
result = 0
for ch in apiName:
result = ROR(result, 0x13)
result += ord(ch)
return result
You need to change the order of the lines so that the last letter also gets the results of the other function -
for ch in apiName:
result += ord(ch)
result = ROR(result, 0x13) # What you did was change the result later
Related
To apply a Vigenere coding, we have to shift the letters but not all by the same number. The key is this time a keyword which each letter gives us the shift to be done (taking A for a shift of 0, B for a shift of 1 ...).
Let's take an example to explain the method: Let's imagine that the keyword is "MATHS" and the word to code is "PYTHON".
To code P, I shift the number corresponding to M, i.e. 12 (because we start at 0 with A) which gives me B as coding for P.
Let's move on to Y: I shift it by the number corresponding to A, i.e. 0, so Y is the coding for Y here.
Let's go to T which is shifted by the number corresponding to T, i.e. 19, so T becomes M once shifted
And so on.
import string
def vigenere_cipher(msg, shift):
encrypted = ''
for i,j in zip(msg,shift):
new_index = ( string.ascii_uppercase.index(i) + string.ascii_uppercase.index(j) ) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
If our keyword is too short we start again at the beginning of the word, i.e. N will be shifted by the number corresponding to M.
My problem right here is actually with the last part, How I can simply say that if the keyword is too short we start again at the beginning of the word ?
Because only "PYTH" part is encrypted to "BYMO" with MATH as a key but not the "ON"
I think the main issue here is that you're zipping both msg and shift together, when you don't actually need to do so. You already understand the concept of using % to guarantee that you stay on a number smaller than your max number, so I'll modify your function to also use % to select which character from shift you want to use
import string
def vigenere_cipher(msg, shift):
encrypted = ''
shift_length = len(shift)
for i, char in enumerate(msg):
new_index = ( string.ascii_uppercase.index(char) + string.ascii_uppercase.index(shift[i % shift_length]) ) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
Just add the line shift = shift * (len(msg) // len(shift) + 1) at the start of the function so shift is repeated until it's longer than msg (e.g. this line turns MATH into MATHMATH)
import string
def vigenere_cipher(msg, shift):
shift = shift * (len(msg) // len(shift) + 1)
encrypted = ''
for i,j in zip(msg,shift):
new_index = (string.ascii_uppercase.index(i) + string.ascii_uppercase.index(j)) % 26
encrypted += string.ascii_uppercase[new_index]
return encrypted
print(vigenere_cipher('PYTHON', 'MATH'))
Output: BYMOAN
I have constructed a Vigenere cipher function that works reasonably well, except for the fact that it does not pass the coding test that I'm required to run it through.
This is due to the fact that I'm using the ordinal values, while the test is expecting me to use a function to just rotate through a string letters, I think.
I have already run through the issue of dealing with non-alpha characters and got it to work with both upper case and lower case characters. However, it seems to fall apart if the key has any variance of upper case or lower case characters i.e. the key is lower case but the plain text is upper.
def encrypt(text, key):
cipher_text = []
key = list(key)
if len(text) == len(key):
return(key)
else:
for i in range(len(text) -
len(key)):
key.append(key[i % len(key)])
for i in range(len(text)):
a = text[i]
if a.isalpha() and a.islower():
x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
cipher_text.append(chr(x))
elif a.isalpha() and a.isupper():
x = ((ord(text[i]) + ord(key[i])-65) % 26 + 65)
cipher_text.append(chr(x))
else:
cipher_text.append(a)
return("" . join(cipher_text))
def main():
mess = input(str("What is message?"))
key = input("What is key?")
print(encrypt(mess, key))
if __name__ == '__main__':
main()
For vigenere.encrypt('BaRFoo', 'BaZ')
You should have returned this:
'CaQGon'
But you actually returned this:
'PtDTha'
from your single example it seems like the key is case insensitive:
def encrypt_letter(c, k):
if c.isupper():
base = ord('A')
else:
base = ord('a')
return chr((ord(c) - base + ord(k) - ord('a')) % 26 + base)
def encrypt(text, key):
key = key.lower()
return "".join([encrypt_letter(text[i], key[i % len(key)]) for i in range(len(text))])
def main():
print(encrypt('BaRFoo', 'BaZ'))
if __name__ == '__main__':
main()
First of all, I don't program in python, so excuse my form. I however tested everything in online compiler.
Before I answer your question, I'm not sure about this segment:
if len(text) == len(key):
return(key)
else:
for i in range(len(text) -
len(key)):
key.append(key[i % len(key)])
I read that as "If the key has the same length as plaintext, the key is the ciphertext", which obviously isn't true, unless the key is "aaaaaaaaa...". I would expect something like this:
if len(text) > len(key):
for i in range(len(text) -
len(key)):
key.append(key[i % len(key)])
# else:
# I don't care - the key is long enough
From Kfir Dadosh's answer I'd also point out, that you don't actually need this step and might as well directly access the key as key[i % len(key)].
As for the issue you were referring to. You only check whether plaintext (message) is lowercase or uppercase and change the key (let's call it normalization - the act of converting letter to number in the range 0-25 denoting it's position in alphabet) according to that.
if a.isalpha() and a.islower():
x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
Here you take raw ^ ^
ascii value instead of | |
normalized (0-25) number |
|
Here you normalize the key according to the
message case
Following this are some heavy spoilers, so if you understand and want to solve the problem yourself, then stop reading here.
I'd suggest to separate the normalization and encryption steps, to avoid the confusion. Let's get rid of the special characters first instead of last, because it's easy to do and we'll only have to worry about letters:
if not (text[i].isalpha()):
cipher_text.append(text[i])
continue; # done with this symbol - skip to the next one
Then normalize the letters, with the help of built in method. Let's use variables p for plaintext, k for key and c for ciphertext (later):
p = ord(text[i].lower()) - ord('a') # converts to lowercase, then to number
k = ord(key[i].lower()) - ord('a') # both key AND plaintext
I used ord('a') instead of 65 as I'm used to that and find it clearer, but it is a matter of preference and language traditions (which I'm not accustomed with).
Then the encryption step:
c = (p + k) % 26;
And now to restore the capitalization. We destroyed it in the variables p and k, but we still have their source array text[] with intact values. We can use that to restore the capitalization (assuming the case should be inherited from plaintext):
if (text[i].islower()):
cipher_text.append(chr(c + ord('a')))
elif (text[i].isupper()):
cipher_text.append(chr(c + ord('A')))
That completes the main loop. Feel free to modify it to be more python compliant.
for i in range(len(text)):
if not (text[i].isalpha()):
cipher_text.append(text[i])
continue;
p = ord(text[i].lower()) - ord('a')
k = ord(key[i].lower()) - ord('a')
# k = ord(key[i % len(key)].lower()) - ord('a')
# if you skipped the key lengthening process
c = (p + k) % 26;
if (text[i].islower()):
cipher_text.append(chr(c + ord('a')))
elif (text[i].isupper()):
cipher_text.append(chr(c + ord('A')))
else:
# not sure if this can happen in python, but if it does, we're probably
# in trouble
# otherwise it might as well be merged with the elif above
return("" . join(cipher_text))
I want to be able to print a string and format it into a shape. In the code here it formats into a right triangle, but I wanna do other shapes too. The problem is I can't get the string to truncate at each line and continue on, it simply loops at the first character.
this is what it looks like
hhhhhhhhhhhhhhh
hhhhhhhhhhhhh
hhhhhhhhhhh
hhhhhhhhh
hhhhhhh
hhhhh
hhh
h
but I want it to look like this
hellowor
ldhowar
eyout
oday
?
I've been struggling to wrap my head around this concept a lot lately, I can't seem to loop functions within functions properly. I think I'm probably missing some key part of knowledge for indexes or for loops that's stopping me. But if you could show me here, I might be able to learn a bit more about it. I've tried googling this issue to no avail. I appreciate any help.
Here's my code thus far:
text = ('hello world how are you today?')
def word():
for c in text:
return c
def triangle(i, t = 0):
if i == 0:
return 0
else:
print '' * (t + 1) + word() * (i * 2 - 1)
return triangle (i - 1, t + 1)
triangle (8)
edit:
the other thing I added was this:
def triangle(i, t = 0):
if i == 0:
return 0
else:
for c in text:
print '' * (t + 1) + word() * (i * 2 - 1)
return triangle (i - 1, t + 1)
but it yields the same problem, where by it only prints the first letter from 'text'.
How do I loop through each letter?
Thanks. The basic answer is that you're making this too complicated. Start at the front of the string with your initial row; pass the remainder to a recursive call. Don't bother to take individual characters out of the string: just grab the subset you need.
Note that this has two base cases: Either size hits 0, or you run out of message before that.
def triangle(message, size):
# Size = 0: we're done; ran out of rows
if size == 0:
return
# Not enough message left: print it all
if size >= len(message):
print message
# print "size" characters and go to next line
else:
print message[:size]
triangle(message[size:], size-1)
text = "hello world how are you today?"
triangle(text, 8)
print ""
triangle(text, 7)
Output:
hello wo
rld how
are y
ou to
day?
hello w
orld h
ow ar
e yo
u t
od
a
STRING SLICES
The general form is
str[start : end : step]
This gets you the substring from str[start] through str[end-1], inclusive. If you omit any of the arguments, the defaults are
start = 0
end = -1 (through the end of the string)
step = 1
Since we rarely have regular skips through a string, the step argument is almost always defaulted to 1.
I'm trying to make an encryption function that encrypts plaintext messages but the problem is that if i input a key too large that goes past 'Z' then it goes onto greater unicode values.
My code:
def encrypt(var1,var2):
var3 = ""
for i in range(0, len(var1)):
if ord(var1[i])>64 and ord(var1[i])<90:
var3=var3+chr((ord(var1[i])+var2))
elif ord(var1[i])+var2>90:
???
else:
continue
return(var3)
How do I get it to loop 'Z' back to 'A'. I think I have to make an if statement like this but I'm not sure what to put into it.
elif ord(var1[i])+var2>90:
???
Here is my one! Im using the modulus operator to wrap around every 26 numbers (the number of letter between a-z). I also handle upper on lowercase separately.
def encrypt(data, shift):
result = ''
for c in data:
c_num = ord(c)
# is the letter lower case a - z?
if (c_num >= ord('a')) and (c_num <= ord('z')):
# get the letter number from 0 - 26
c_num = c_num - ord('a')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('a')
result += chr(c_num)
# is the letter upper case A - Z?
elif (c_num >= ord('A')) and (c_num <= ord('Z')):
# get the letter number from 0 - 26
c_num = c_num - ord('A')
# shift the number
c_num += shift
# wrap the number every 26 numbers
c_num = c_num % 26
# now increase a by the new amount
c_num += ord('A')
result += chr(c_num)
return result
encrypt('aAbB', 2)
'cCdD'
encrypt('afZz', 2)
'chBb'
Here is the code golf version using list comprehension just for fun!
def encrypt(data, shift):
return ''.join([chr(((ord(c) - ord('a') + shift) % 26) + ord('a')) if ord(c) in range(ord('a'), ord('z')+1) else chr(((ord(c) - ord('A') + shift) % 26) + ord('A')) for c in data])
A straight-forward way would be to check if you have passed beyond Z, and modify the character in that case:
...
if var1[i] >= 'A' and var1[i] <= 'Z':
translated_char = chr(ord(var1[i])+var2)
if translated_char > 'Z':
# If the resulting character is beyond Z,
# we go 26 characters back
translated_char = chr(ord(translated_char)-26)
# Append the translated character to the output string
var3 += translated_char
...
You may want to consider more descriptive variable names -- you'll thank yourself if you revisit your code after two months :-)
I would recommend using the modulus operator to do what you are wanting. In python that is the % character. In modulus math. X % Y tells us what the remainder of X / Y is. For example. 27 % 26 is 1. Using this you can get your wrap around that you want. Here is a sample bit of code to encrypt a single character
def encrypt_character( valToEncrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToEncrypt) - ord('A')
# Perform the Encryption
retVal = ( x + keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
# end encrypt_character
Now if we feed the character "A" Into our encryption algorithm with a key of 13 we get "N" as shown:
>>> encrypt_character("A", 13)
'N'
The decrypt algorithm is very similar, except you do subtraction instead of addtion
def decrypt_character( valToDecrypt, keyVal ):
# Update the character to be our standard Alphabet mapping
# A -> 0; B->1 ... Z -> 25
x = ord(valToDecrypt) - ord('A')
retVal = ( x - keyVal ) % 26
# Translate back to the standard ASCII mapping of the character
# for display in python and translate it back into a string
retVal = chr(retVal + ord('A'))
return retVal
To encrypt a string you can use the following function:
from re import sub
def encrypt_message( message, key ):
# Convert the message text into a plain text with all spaces and
# punctuation removed.
plainText = sub(r'[^A-Z]', '', message.upper())
cipherText = ""
charIndex = 0
# Encrypt the message 1 character at a time
while charIndex < len(plainText):
cipherText += \
encrypt_character( plainText[charIndex], key)
charIndex += 1
return cipherText
This function can be called:
>>> encrypt_message("HELLO World!", key=23)
'EBIILTLOIA'
The decryption function is very similar to the encryption function, except it calls the decrypt utility instead of the encrypt utility.
Assume I have this (currently return-less) function:
def codepoint_convert(text, offset):
codepoint = text[offset]
if codepoint <= 0x01:
output = "\n"
elif codepoint >= 0x09 and codepoint <= 0x12: # digits
output = chr(0x30 + (codepoint-0x09))
elif codepoint >= 0x13 and codepoint <= 0x2C: # uppercase letters
output = chr(0x41 + (codepoint-0x13))
elif codepoint >= 0x2D and codepoint <= 0x46: # lowercase letters
output = chr(0x61 + (codepoint-0x2D))
elif codepoint >= 0x47 and codepoint <= 0x62: # multi-byte codepoints
offset += 1
codepoint = (codepoint << 8) + text[offset]
output = cp_dict[codepoint]
else:
print("Invalid codepoint at 0x%08X" % offset)
offset += 1
How would I best update (i.e. increment and append, respectively) both offset and output in a while loop defined like this?:
def main():
text = "\x0A\x0B\x0C\x01"
offset = 0
output = ''
while offset < len(text):
I have previously used two approaches:
1
def convert_codepoint(text, offset, output):
# A: see first code snippet
# B: concatenate to "output" (+=) instead of assigning (=)
return [offset, output]
def main():
text = "\x0A\x0B\x0C\x01"
offset = 0
output = ''
while offset < len(text):
offset, output = convert_codepoint(text, offset, output)
2
offset = 0 # global variable
def convert_codepoint(text, offset):
global offset
# A: see first code snippet
return output
def main():
text = "\x0A\x0B\x0C\x01"
output = ''
while offset < len(text):
output += convert_codepoint(text, offset)
To me, the first approach is confusing, because it looks like it replaces the offset and output variables instead of updating them, since it uses = instead of += (it does not seem like I could somehow use += in a list-assignment in Python 3.4.2 anyway, since it throws a SyntaxError ("illegal expression for augmented assignment")). And the use of a list as a return value does not seem so port-friendly either.
My gripe with the second approach is that it uses a global variable. I want it to be possible to call convert_codepoint() (e.g. if the script is imported as a module) without having to have a global variable defined. The offset variable may need to be re-initialized from the main function, too, so that could get messy.
Any other approach I could try, to update the variables locally, in a nice and clear way?
Why not have a function that returns the next output and offset, then append the next output element to your output list:
def get_next_output_offset_pair(text, offset):
#A: Adapt first code snippet
return [next_offset, next_output]
def main():
text = "\x0A\x0B\x0C\x01"
offset = 0
output = ''
while offset < len(text):
offset, next_output = get_next_output_offset_pair(text, offset)
output.append(next_output)
Or, you could even do this:
next_offset, next_output = get_next_output_offset_pair(text, offset)
output.append(next_output)
offset = next_offset
I think your first solution is perfectly clear, but your code should make intuitive sense to you without making the next maintainer's life difficult.