Haskell 中的字符串异或
XORing strings in Haskell
我想编写一个使用 XOR 密码加密文本的程序。这就是我现在拥有的:
-- XORres 2 strings
stringXor :: String -> String -> String
stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
-- encryption and decryption
encDec :: String -> String -> String
encDec text key = stringXor (take (length text) (cycle key)) text
但是encDec "this is a test" "k"
的输出是
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\US"
虽然我期待 1f0302184b02184b0a4b1f0e181f4b
。
这可能是什么问题?我搜索过类似的问题,但这不是很有帮助。
stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
您将 chr
映射到 XOR 的结果。这会产生每个 ASCII 值的字符。要将结果显示为十六进制,您将需要找到一个不同的函数来替换 chr
或自己编写一个。
旁注:在密码学中,通常使用 Base64 符号而不是十六进制来编码二进制数据,因为它使用更少的字符(因此内存或网络带宽更少)来表示相同的二进制序列。
问题出在 chr :: Int -> Char
。此函数将 Int
转换为相应的字符,但 不是 该数字的十六进制表示形式。
例如,您可以使用 intToDigit :: Int -> Char
:
定义效用函数
import Data.Char(intToDigit)
toHex2 :: Int -> String
toHex2 h = map intToDigit [d, m]
where (d, m) = divMod h 16
那么我们可以将函数实现为:
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith xor (map ord s) (map ord t))
或:
import Data.Function(on)
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith (xor `on` ord) s t)
然后我们得到:
Prelude Data.Char Data.Bits> encDec "this is a test" "k"
"1f0302184b02184b0a4b1f0e181f"
注意这里不需要用length
,其实没有长度更安全,直接用cycle
:
encDec :: String -> String -> String
encDec text key = stringXor (cycle key) text
你正在获得1f0302184b02184b0a4b1f0e181f4b
:
> "\x1f\x03\x02\x18\x4b\x02\x18\x4b\x0a\x4b\x1f\x0e\x18\x1f\x4b"
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\USK"
...这正是您从 encDec
看到的输出(在您的预期输出中似乎是一个简单的复制粘贴错误)。
我想编写一个使用 XOR 密码加密文本的程序。这就是我现在拥有的:
-- XORres 2 strings
stringXor :: String -> String -> String
stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
-- encryption and decryption
encDec :: String -> String -> String
encDec text key = stringXor (take (length text) (cycle key)) text
但是encDec "this is a test" "k"
的输出是
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\US"
虽然我期待 1f0302184b02184b0a4b1f0e181f4b
。
这可能是什么问题?我搜索过类似的问题,但这不是很有帮助。
stringXor s t = map chr $ zipWith xor (map ord s) (map ord t)
您将 chr
映射到 XOR 的结果。这会产生每个 ASCII 值的字符。要将结果显示为十六进制,您将需要找到一个不同的函数来替换 chr
或自己编写一个。
旁注:在密码学中,通常使用 Base64 符号而不是十六进制来编码二进制数据,因为它使用更少的字符(因此内存或网络带宽更少)来表示相同的二进制序列。
问题出在 chr :: Int -> Char
。此函数将 Int
转换为相应的字符,但 不是 该数字的十六进制表示形式。
例如,您可以使用 intToDigit :: Int -> Char
:
import Data.Char(intToDigit)
toHex2 :: Int -> String
toHex2 h = map intToDigit [d, m]
where (d, m) = divMod h 16
那么我们可以将函数实现为:
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith xor (map ord s) (map ord t))
或
import Data.Function(on)
stringXor :: String -> String -> String
stringXor s t = concatMap toHex2 (zipWith (xor `on` ord) s t)
然后我们得到:
Prelude Data.Char Data.Bits> encDec "this is a test" "k"
"1f0302184b02184b0a4b1f0e181f"
注意这里不需要用length
,其实没有长度更安全,直接用cycle
:
encDec :: String -> String -> String
encDec text key = stringXor (cycle key) text
你正在获得1f0302184b02184b0a4b1f0e181f4b
:
> "\x1f\x03\x02\x18\x4b\x02\x18\x4b\x0a\x4b\x1f\x0e\x18\x1f\x4b"
"\US\ETX\STX\CANK\STX\CANK\nK\US\SO\CAN\USK"
...这正是您从 encDec
看到的输出(在您的预期输出中似乎是一个简单的复制粘贴错误)。