OneTimePad实现失败。也许是一个流问题?

时间:2010-09-15 20:32:49

标签: java encryption cryptography stream

我有一段时间并且决定实施一次性垫片,仅仅是为了娱乐和自我教育。现在我最终得到了一个奇怪的数据行为。它让我疯狂^^。你能帮帮我吗?提前谢谢。

有一种加密方法可以作为争论:

  • 明文<{1}}
  • 用于密文的InputStream
  • 和密钥的OutputStreams

有一种解密方法可以作为争论:

  • 用于密文的OutputStreams
  • 密钥的InputStream
  • 明文的InputStream

有一种测试和调试代码的主要方法。这是班级:

OutputStreams

现在这是我遇到的问题。我加密纯文本并解密它immediatley,但加密的纯文本与原始文本不同。我为调试做了一些调整,看起来,我在加密期间写的数据与我在解密过程中读取的数据不一样。自己看一下输出:

 ------------------------------------ encrypting
 plain key cipher
 84 25 109
 104 239 87
 105 86 191
 115 74 189
 32 100 132
 105 17 122
 115 211 70
 32 147 179
 109 104 213
 121 118 239
 32 139 171
 112 244 100
 108 196 48
 97 181 22
 105 226 75
 110 94 204
 32 156 188
 116 92 208
 101 91 192
 120 165 29
 116 177 37
 46 49 95
 plaintext: This is my plain text.
 ciphertext: mW���zF���d0K̼��%_
 key: �VJdӓhv��ĵ�^�\[��1
 ------------------------------------ decrypting
 plain key cipher
 84 25 109
 152 239 87
 48 191 239
 2 189 191
 103 86 189
 165 74 239
 91 100 191
 172 17 189
 28 211 239
 44 147 191
 85 104 189
 4 118 122
 169 239 70
 48 191 239
 2 189 191
 50 239 189
 48 191 239
 2 189 191
 7 196 189
 58 181 239
 48 239 191
 2 191 189
 89 189 100
 46 94 48
 217 239 22
 116 191 75
 15 189 204
 96 92 188
 148 91 239
 48 239 191
 2 191 189
 50 189 239
 48 239 191
 2 191 189
 160 189 29
 12 49 37
 96 -1 95
 plaintext: T�0g�[�,U�020:0Y.�t`�020�`

这看起来很奇怪。有什么差异来自哪些建议?

提前致谢。

3 个答案:

答案 0 :(得分:2)

有两个问题:

  1. 使用String#getBytes来获取要反馈的字节数。这意味着它们经历了一轮字符串解码和编码。请注意,密钥字节序列在加密和解密时并不相同。您应该使用ByteArrayOutputStream#toByteArray
  2. Math.abs(cipherTextByte - keyByte) % 256错了。 (0 - 1)(mod 256)= 255而不是1.您应该使用(256 + cipherTextByte - keyByte) % 256

答案 1 :(得分:1)

您可以使用xor,而不是添加和减去然后使用%256。这样就完成了同样的任务,数学怪异程度更低。 a ^ b不关心标志或遗留物或任何垃圾,从不超出其参数范围(byte1 ^ byte2将始终为字节大小),并且它很容易可逆。

至于你遇到问题的原因:当你使用abs来包装你的数字时,你最终会打破某些与二进制补码一致的假设。 (abs(-x)256-x在大多数情况下并不相同。)这使得你的数学不稳定,因为符号位最终会在随机播放中丢失 - 其他位被错误地翻转因为它,并且因为你用abs抛出了标志而无法翻转。

例如,假设你的明文字节是65('A',如果你关心的话),你的RNG为填充字节提供192。 abs(65+192) % 256会将1作为您的“密文”。但是当你解密它时,1-192 == -191。在8位的二进制补码中,对应于65,但abs(1-192)给出191.

您最好使用(cipherTextByte + (256 - keyByte)) % 256。在示例中,1 +(256-192)== 1 + 64 == 65。

另外,正如已经提到的,一旦你有加密字节,它们应该被视为 - bytes 。它们不再形成一串;它们应该始终(或者更确切地说,直到解密)是一个字节序列。编码等可以巧妙地修改数据,在这里添加一个字节或在那里转换某些内容,当你尝试解密时,你最终可能会变成垃圾。但是你的例子中最大的问题是数学,而不是编码问题。

答案 2 :(得分:0)

从编码的角度来看,使用一次性垫衍生物可能更简单, 使用单个Unicode字符而不是单个位?

规范位于 http://longterm.softf1.com/specifications/txor/index.html

安全性和证明几乎相同,但不需要处理任何字符编码,UTF-8等部分。