问题
I reverse engineered to decrypt, but do not get the expected result.
For example, entering
Lipps${svph%
with offset 4 should result in
Hello World!
but I get
ello´world³
What did I do wrong?
code = input("Enter text to decrypt: ")
distance = int(input("Enter number of offset: "))
plainText = ''
for ch in code:
ordValue = ord(ch)
cipherValue = ordValue - distance
if cipherValue < ord('a'):
cipherValue = ord('z') - \
(distance - (ord('a') - ordValue + 1))
plainText += chr(cipherValue)
print(plainText)
回答1:
OK, I got it working for a-z and gave you a little test framework to enter/check automatically rather than typing it in every time.
def dowork(code, distance, lower, upper):
bounddown, boundup = ord(lower), ord(upper)
plaintext = ""
for ch in code:
ordValue = ord(ch)
cipherValue = ordValue - distance
if cipherValue < bounddown:
cipherValue = boundup - bounddown - ordValue +1
plaintext += chr(cipherValue)
return plaintext
dataexp = [
(("jgnnq",2, 'a', 'z'),"hello"),
]
for input_, exp in dataexp:
got = dowork(*input_)
msg = "exp:%s:%s:got for %s" % (exp, got, inp)
if exp == got:
print("good! %s" % msg)
else:
print("bad ! %s" % msg)
This prints
good! exp:hello:hello:got for ('jgnnq', 2, 'a', 'z')
Now all you need to do is add an extra item to the dataexp list, something like
(("Lipps${svph%", 4, <lowerbound>, <upperbound char>), "Hello World!")
once you have the upper and lower bound figured out it should work. Notice that I didn't know caesar code, I just copied yours directly but restructured it a bit.
what *_input
does is to take those 4 values in that tuple (more or less a list) and assign them to code, distance, lower, upper
in the dowork
function.
lower
is what corresponds to a
in your code and upper
is z
.
exp is what you expect and exp == got
just checks whether what the function returned is correct or not. once you get the function correct it should work for both my simplistic a-z
, 2 distance, hello
test and your more complicated 4 distance but including punctuation
lower and upper bounds
your 2 strings, input and output, are Lipps${svph%
and Hello World!
. That means all of these characters need to fall within your upper and lower ord values, right? So the minimum ord position of all those is your lower
and the max is your upper
. Now, I'm not the guy from Cryptonomicon and I can't ever remember if ord(a) < ord(A) or not, let alone the punctuations. So you'll have to kind tinker with that, which is why I based my test on only the lower case letters. I'd add 0-9 though.
final version
This does not need you to figure out which character to put at lowest bound and which at upper. We take lower = 32 (start of printable chars), upper = 255. That way punctuations, upper and lower case, digits, their ord values dont matter anymore.
#full ASCII range, you can go to town on entering whatever you want
bounddown, boundup = 32, 255
plaintext = ""
for ch in code:
ordValue = ord(ch)
cipherValue = ordValue - distance
if cipherValue < bounddown:
cipherValue = boundup - bounddown - ordValue +1
plaintext += chr(cipherValue)
回答2:
Here's a implementation for encrypting and decrypting when the input for characters within a certain range (in this case a-z
). You can adapt this for other ranges depending on what you need.
def caesar(text, offset, decrypt=False):
lower_bound, upper_bound = ord('a'), ord('z')
if decrypt:
offset = (upper_bound - lower_bound + 1) - offset
result = ''
for t in text:
o = ord(t)
if lower_bound <= o <= upper_bound:
new_t = o + offset
if new_t > upper_bound:
new_t = (new_t % upper_bound) + lower_bound - 1
result += chr(new_t)
else:
result += t
return result
Then you can call:
caesar(caesar('hello world!', 2,), 2, True)
# => 'hello world!'
来源:https://stackoverflow.com/questions/60795235/reverse-engineer-ceasar-cipher