Codec.Crypto.RSA :(解密加密)/ =使用PKCS#1 v1.5填充时的id?

时间:2012-04-19 04:55:13

标签: haskell encryption rsa padding

我正在使用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(默认为OAEP 1 )和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

1 个答案:

答案 0 :(得分:11)

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

问题在于

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,因此不是> high

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

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