简体   繁体   English

在python中返回多个值时的不同结果(Cryptopal挑战)

[英]Different results when return multiple values in python (Cryptopal challenges)


I'm working on problem 3(set 1) of the cryptopals challenges ( https://cryptopals.com/sets/1/challenges/3 ) 我正在研究cryptopals挑战的问题3(set 1)( https://cryptopals.com/sets/1/challenges/3
I've already found the key ('x') and decrypted the message ('Cooking mcs like a pound of bacon') Here is my code: 我已经找到了密钥('x')并解密了消息('像一磅培根一样烹饪mcs')这是我的代码:

from hexToBase64 import hexToBinary
from fixedXOR import xorBuffers

def binaryToChar(binaryString):
    asciiValue = 0
    for i in range(int(len(binaryString))-1,-1,-1):
        if(binaryString[i] == '1'):
          asciiValue = asciiValue + 2**(7-i)
    return chr(asciiValue)

def decimalToBinary(number):
    binaryString = ""
    while (number != 0):
        bit = number % 2 
        binaryString = str(bit) + binaryString
        number = int(number/2)
    while(len(binaryString) < 8): 
        binaryString = "0" + binaryString
    return binaryString

def breakSingleByteXOR(cipherString):
    decryptedMess = ""
    lowestError = 10000
    realKey = ""
    for i in range(0,128):
        errorChar = 0 
        tempKey = decimalToBinary(i)
        tempMess = ""
        for j in range(0,len(cipherString),2):
            #Take each byte of the cipherString 
            cipherChar = hexToBinary(cipherString[j:j+2])
            decryptedChar = binaryToChar(xorBuffers(cipherChar,tempKey))
            asciiValue = ord(decryptedChar)
            if (not ((asciiValue >= 65) and (asciiValue <= 90)) \
               or ((asciiValue >= 90) and (asciiValue <= 122)) \
               or ( asciiValue == 32 )):
               # if the character is not one of the characters ("A-Z" or "a-z"
               # or " ") consider it as an "error" 
               errorChar += 1 
            tempMess = tempMess + decryptedChar
        if(errorChar < lowestError):
            lowestError = errorChar
            decryptedMess = tempMess
            realKey = chr(i)
    return (realKey,decryptedMess)



if __name__ == "__main__":
    print(breakSingleByteXOR("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736")) 

The problem is when I use the function breakSingleByteXOR to return one value (decryptedMess), it came out okay "cOOKING mcS LIKE A POUND OF BACON" 问题是,当我使用功能breakSingleByteXOR返回一个值(decryptedMess)时,结果“显示mcS像培根一样”没问题
But when I return 2 values with the function (as the code above - (key,decryptedMess)), I received a weird result ('x', 'cOOKING\\x00mc\\x07S\\x00LIKE\\x00A\\x00POUND\\x00OF\\x00BACON'), can anyboby explain to me why this is the case? 但是当我使用函数返回2个值时(如上面的代码-(key,decryptedMess)),我收到了一个奇怪的结果('x','cOOKING \\ x00mc \\ x07S \\ x00LIKE \\ x00A \\ x00POUND \\ x00OF \\ x00BACON') ,任何人都可以向我解释为什么会这样吗?

Tbh, I'm learning python as I'm doing the challenges so hopefully I dont trigger anyone with these code.... I'd also really appreciate it if anyone could give me some advices on writing good python code Tbh,我在学习python的同时也正面临挑战,因此希望我不会用这些代码触发任何人。...如果有人可以给我一些有关编写良好python代码的建议,我也将非常感谢
Thanks guys :D 谢谢大家:D

It's true that the reason for the difference in the printed string is a quirk of the print function. 的确,打印字符串不同的原因是print功能的怪癖。

The deeper problem with that program is that it's not producing the correct answer. 该程序的更深层问题是它无法产生正确的答案。 That's because the big ugly if that tries to decide whether a decrypted character is in the acceptable range is incorrect. 那是因为if试图确定解密的字符是否在可接受的范围内,那很丑陋if这是不正确的。

It's incorrect in two ways. 这有两种错误。 The first is that (asciiValue >= 90) should be (asciiValue >= 97) . 第一个是(asciiValue >= 90)应该是(asciiValue >= 97) A better way to write all of those expressions, which would have avoided this error, is to express them as (asciiValue >= ord('a')) and (asciiValue == ord(' ')) and so on, avoiding the inscrutable numbers. 编写所有这些表达式的更好方法(可以避免此错误)是将它们表示为(asciiValue >= ord('a'))(asciiValue == ord(' ')) ,依此类推,避免使用难以理解的数字。

The second way is that the expressions are not properly grouped. 第二种方法是表达式未正确分组。 As they stand they do this: 当他们站立时,他们这样做:

character is not in the range 'A' to 'Z',
    or character is in the range 'a' to 'z',
    or character is 'space',
        then count this as an error

so some of the characters that should be good (specifically 'a' through 'z' and space) are counted as bad. 因此,一些本应该不错的字符(特别是从“ a”到“ z”以及空格)被视为坏字符。 To fix, you need to rework the parentheses so that the condition is: 要解决此问题,您需要对括号进行重新处理,以使条件为:

character is not in the range 'A' to 'Z',
    and character is not in the range 'a' to 'z',
    and character is not space,
        then count this as an error

or (this is style you were trying for) 或(您正在尝试的样式)

character is not (in the range 'A' to 'Z'
    or in the range 'a' to 'z'
    or a space)

I'm not going to give you the exact drop-in expression to fix the program, it'll be better for you to work it out for yourself. 我不会为您提供确切的插入式表达式来修复该程序,让您自己解决这个问题会更好。 (A good way to deal with this kind of complexity is to move it into a separate function that returns True or False . That makes it easy to test that your implementation is correct, just by calling the function with different characters and seeing that the result is what you wanted.) (处理这种复杂性的一种好方法是将其移动到一个返回TrueFalse的单独函数中。通过调用具有不同字符的函数并查看结果,可以轻松地测试实现是否正确是你想要的。)

When you get the correct expression, you'll find that the program discovers a different "best key" and the decrypted string for that key contains no goofy out-of-range characters that behave strangely with print . 当您获得正确的表达式时,您会发现程序发现了一个不同的“最佳密钥”,并且该密钥的解密字符串不包含愚蠢的超出范围的字符,这些字符在print上的行为异常。

The print function is the culprit - it is translating the characters \\x00 and \\x07 to ASCII values when executed. print功能是罪魁祸首-执行时它将\\x00\\x07字符\\x07为ASCII值。 Specifically, this only occurs when passing a string to the print function, not an iterable or other object (like your tuple ). 具体来说,只有在将字符串传递给print函数时,才会发生这种情况,而不是将迭代对象或其他对象(例如tuple )传递给它。

This is an example: 这是一个例子:

>>> s = 'This\x00string\x00is\x00an\x00\x07Example.'

>>> s
'This\x00string\x00is\x00an\x00\x07Example.'

>>> print(s)
This string is an Example.

If you were to add the string s to an iterable ( tuple , set , or list ), s will not be formatted by the print function: 如果要将字符串s添加到可迭代( tuplesetlist )中,则将不会通过print函数set s格式:

>>> s_list = [s]
>>> print(s_list)  # List
['This\x00string\x00is\x00an\x00\x07Example.']

>>> print(set(s_list))  # Set
{'This\x00string\x00is\x00an\x00\x07Example.'}

>>> print(tuple(s_list))  # Tuple
('This\x00string\x00is\x00an\x00\x07Example.')

Edit 编辑

Because the \\x00 and \\x07 bytes are ASCII control characters, ( \\x00 being NUL and \\x07 being BEL), you can't represent them in any other way. 因为\\x00\\x07字节是ASCII控制字符( \\x00是NUL, \\x07是BEL),所以您无法用其他任何方式表示它们。 So one of the only ways you could strip these characters from the string without printing would be to use the .replace() method; 因此,无需打印就可以从字符串中剥离这些字符的唯一方法之一就是使用.replace()方法。 but given \\x00 bytes are being treated as spaces by the terminal, you would have to use s.replace('\\x00', ' ') to get the same output, which has now changed the true content of the string. 但是如果终端将\\x00字节视为空格,则必须使用s.replace('\\x00', ' ')来获得相同的输出,该输出现在更改了字符串的真实内容。

Otherwise when building the string; 否则在构建字符串时; you could try and implement some logic to check for ASCII control characters and either not add them to tempMess or add a different character like a space or similar. 您可以尝试实现一些逻辑来检查ASCII控制字符,而不是将它们添加到tempMess或不添加其他字符(例如空格或类似字符)。

References 参考

ASCII Wiki: https://en.wikipedia.org/wiki/ASCII ASCII Wiki: https//en.wikipedia.org/wiki/ASCII

Curses Module: https://docs.python.org/3.7/library/curses.ascii.html?highlight=ascii#module-curses.ascii (Might be useful if you wish to implement any logic). 诅咒模块: https ://docs.python.org/3.7/library/curses.ascii.html?highlight = ascii#module- curses.ascii (如果您希望实现任何逻辑,可能会很有用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM