【问题标题】:Codec.Crypto.RSA: (decrypt . encrypt) /= id when PKCS#1 v1.5 padding is used?Codec.Crypto.RSA: (decrypt . encrypt) /= id 当使用 PKCS#1 v1.5 填充时?
【发布时间】:2012-04-30 14:24:44
【问题描述】:

我正在使用 Codec.Crypto.RSA 加密一个随机字符串,该字符串以 base64 表示形式通过套接字传递给外部进程。外部进程(使用 openssl 解密的 ruby​​ 程序)有时无法解密消息。

为了调试它,我在 haskell 中设置了一个简单的脚本,用于加密和解密固定消息,所有这些都没有 base64 编码/解码。让我感到困惑的是,这个非常简单的程序在几次迭代后导致失败。解密后的密文不等于原始消息,尽管消息包含在解密中(在一些不可打印的字符之后)。

代码如下:

import Crypto.Random
import qualified Codec.Crypto.RSA as RSA
import qualified Data.ByteString.Lazy.Char8 as L

m :: L.ByteString
m = L.pack "11111222223333344444555556666600"

main = do
  gen <- newGenIO :: IO SystemRandom
  let (pub, priv, _) = RSA.generateKeyPair gen 1024
  doStuff pub priv

doStuff pub priv = do
  gen <- newGenIO :: IO SystemRandom
  let (e,_) = RSA.encrypt' RSA.UsePKCS1_v1_5 gen pub m
  let d = RSA.decrypt' RSA.UsePKCS1_v1_5 priv e

  if (m == d)
    then do
      putStrLn "SUCCESS"
      doStuff pub priv
    else do
      putStrLn "FAILED"
      putStrLn $ "expected: " ++ show m
      putStrLn $ "got:      " ++ show d

由于 Codec.Crypto.RSA 的测试套件通过了,我的程序肯定有问题。

RSA.encrypt' RSA.UsePKCS1_v1_5替换为RSA.encrypt(默认为OAEP1)和RSA.decrypt' RSA.UsePKCS1_v1_5替换为RSA.decrypt后,故障不再触发。

有人看到这里出了什么问题吗?


[1]我打算以后用OAEP,但是生成的密文由于某种原因不能用echo ciphertext | openssl rsautl -oaep -inkey keypair.pem -decrypt解密,这是另一个问题。

更新: 要使 OAEP 与 OpenSSL 一起工作,必须使用 SHA-1 作为散列函数:

cryptOptions :: RSA.EncryptionOptions
cryptOptions = RSA.UseOAEP sha1' (RSA.generate_MGF1 sha1') BS.empty
  where sha1' = bytestringDigest . sha1

-- then, to encrypt
enc = RSA.encrypt' cryptOptions gen pubkey

【问题讨论】:

    标签: haskell encryption rsa padding


    【解决方案1】:

    您的代码没有问题,这是使用过的库中的错误。

    问题是

    generate_random_bytestring :: CryptoRandomGen g => g -> Int64 -> (ByteString, g)
    generate_random_bytestring g 0 = (BS.empty, g)
    generate_random_bytestring g x = (BS.cons' first rest, g'')
     where
      (rest, g')   = generate_random_bytestring g (x - 1)
      (first, g'') = throwLeft $ crandomR (1,255) g'
    

    它应该生成一个给定长度的随机ByteString,没有 0 字节。

    破解Codec.Crypto.RSA 的源代码来测试它,我很快就会收到一个 0 字节错误。

    这意味着解码后的消息被认为比实际要长,而且前面有一些垃圾。

    具体的错误是crandomR 有时会由于crandomR_Num 中的错误而产生一个 0 字节:

            Right (bs, g') ->
                    let res = fromIntegral $ fromIntegral low + (bs2i bs .&. mask)
                    in if res > high then go g' else Right (res, g')
    

    这里,mask0xFF(255),low是1。如果生成的不受限制的字节是255,那么

    res = fromIntegral 256
    

    这是 0,因此不是 &gt; high

    该错误应该已在monadcryptorandom 的下一个版本(0.4.1)中修复,该版本即将到期已经在hackage上。

    据我所知,OAEP 方法不受影响,因为它们使用不同的填充方案将块填充到所需的长度。

    【讨论】:

    • 这很有帮助。谢谢!
    • 我没有在 monadcryptorandom 的错误跟踪器中找到这个错误,也没有看到任何关于即将发布的版本的信息。您知道软件包作者即将发布下一个版本吗?
    • 不,我已经向作者/维护者发送了有关该错误的邮件。由于这是一件相当重要的事情,我推断托马斯会尽快修复它并毫不拖延地推出修复程序。我想我也要把它添加到错误跟踪器中。
    • 修复并上传为 monadcryptorandom-0.4.1 感谢你们俩!提问者的程序现在打印出非常无聊的无数行“SUCCESS”。
    • 现在就是我所说的答案!
    猜你喜欢
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多