【问题标题】:Is 300ms for encrypting and then decrypting a single 8 * 1K message an acceptable RSA performance? [closed]加密和解密单个 8 * 1K 消息的 300 毫秒是可接受的 RSA 性能吗? [关闭]
【发布时间】:2012-04-09 14:46:23
【问题描述】:

注意: 对于那些无法比提出无聊、愚蠢的 cmets 甚至建议关闭有效问题的人来说,请在此处查看已接受的答案:Using GNU/Linux system call `splice` for zero-copy Socket to Socket data transfers in Haskell 作为一个很好的例子,说明如何为那些真正的人提供适当的帮助寻求建设性的答案!


您好,我刚刚在 Mathematica 8 的文档中阅读 PowerMod 并想测试 Haksell RSA 包 (ghc --make -O2 -O3 -fllvm -optlo-O3 test.hs):

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Monad
import System.Random
import Codec.Crypto.RSA
import Data.ByteString.Lazy
import Data.ByteString.Char8

import Criterion.Main
import Criterion.Config

main :: IO ()
main = do
  print m1
  print m4
  print m8
  defaultMainWith defaultConfig (return ()) [
    bgroup "RSA" [
       bench "1" $ ed m1
     , bench "4" $ ed m4
     , bench "8" $ ed m8
     ]
   ]

m1 = fromChunks [ Data.ByteString.Char8.replicate (1*1024) '0' ]
m4 = fromChunks [ Data.ByteString.Char8.replicate (4*1024) '0' ]
m8 = fromChunks [ Data.ByteString.Char8.replicate (8*1024) '0' ]

ed m = do
  g1 <- newStdGen
  let (el,il,g2) = generateKeyPair g1 1024
  loop 1 g2 el il m

loop :: RandomGen g => Int -> g -> PublicKey -> PrivateKey -> Data.ByteString.Lazy.ByteString -> IO ()
loop n g e i m = do
  let   nn     = n-1
  let  (em,ng) = encrypt g e  m
  let   dm     = decrypt   i em
  when (m == dm) $ Data.ByteString.Char8.putStr "1"
  when (nn > 0 ) $ loop nn ng e i m

也在 Mathematica 中尝试过:

{p, q} = Prime[RandomInteger[{10^4, 10^5}, {2}]];
{p, q, n = p q}
\[Lambda] = CarmichaelLambda[n]
d = NestWhile[#1 + 1 & , Round[n/3], GCD[\[Lambda], #1] =!= 1 &]
e = PowerMod[d, -1, \[Lambda]]
enc = PowerMod[#, e, n] &;
dec = PowerMod[#, d, n] &;
c = ConstantArray[48, 8 1024];
t = Table[c // enc // dec; // AbsoluteTiming, {10}][[All, 1]]

Haskell (m8) 和 Mathematica 案例中的时序相似:

{0.313015, 0.302337, 0.303766, 0.303321, 0.303018, 0.302574, \
0.302511, 0.303958, 0.301411, 0.300820}

对于 RSA 来说,每 8192 字节长的消息 300 毫秒是可接受的性能吗? OpenSSL 或其他实现如何比较?

(测试台:64 位 linux;4xCORE,Intel(R) Core(TM) i5 CPU M 430 @ 2.27GHz)

【问题讨论】:

  • 这是一个评论,而不是一个答案......但说真的,下载 OpenSSL 并尝试一下也不错。
  • 很公平。但是您的问题真正归结为“OpenSSL 在您的体验中有多快?”,这不一定最适合 Stack Overflow。鉴于 OpenSSL 是一种常用的实现,运行它可能足以表明 Mathematica 版本与标准相比有多快/多慢。另外,这将是最公平的比较(在同一台机器上运行!)。
  • 如果有任何帮助,谷歌搜索“OpenSSL benchmark”会返回如下内容:wiki.openwrt.org/inbox/benchmark.openssl,其中包括 RSA 结果。不过,我不确定这些数字是什么意思。
  • 在您的 Haskell 基准测试中,您包括生成密钥对的时间。 a) 是否也包含在 Mathematica 时代,b) 包含它是否明智?
  • 我刚刚修补了 RSA 以使用 CryptoRandomGen,所以如果你没有使用过去几天的版本,那么性能会(轻微)不同。

标签: performance haskell wolfram-mathematica openssl rsa


【解决方案1】:

首先,好问题 - RSA 与 OpenSSL 的性能差异也是我的一个问题。也就是说,这里有一堆没有给出答案的文本。

Haskell RSA 包已更改

我最近将 RSA 从 RandomGen 转移到使用 CryptoRandomGen。您正在使用非常缓慢的StdGen,因此切换到 intel-aes 包中的生成器或 DRBG 包中的HashDRBG(可能是缓冲版本)会有所帮助。

这不是您应该使用公钥密码术的方式

通常,您使用公钥来交换密钥或加密密钥,这样只有接收者才能解密它。您似乎打算使用 RSA 不断加密消息流。 RSA 的性能很少有人关心,正是因为它是一种罕见的操作。

适当的基准测试

正如 Daniel 所说,您目前正在对密钥生成、加密和解密进行一批基准测试。你回答说你不会生成很多密钥,只是做很多 enc/dec 操作......所以你不认为你应该修复基准吗?

此外,您的基准似乎不完整,因此值得怀疑 - 至少它缺少导入。

其他令人担忧的事情

您说“密钥对的随机性[目前] 不重要。”除非它们很重要,否则没有理由担心密码学。

基准测试 奥利也有一个很好的观点。对 OpenSSL 进行基准测试是必经之路。

从命令行(就我的部分答案而言)OpenSSL 会强制您半正确地使用 RSA,因此我们将只对非常小的文件的加密进行基准测试:

dd if=/dev/urandom of=64B bs=64 count=1
openssl genrsa -out test.key 1024
openssl rsa -in test.key -out public.pem -outform PEM -pubout
openssl rsa -in test.key -out private.pem -outform PEM
time openssl rsautl -raw -ssl -encrypt -inkey private.pem -in 64B -out 64B.enc

这给了我们 5 到 12 毫秒的时间。

现在是 Haskell。除了外观上的更改之外,我还使用 CryptoRandomGen 和不那么快但 OK 的 HashDRBG 生成器迁移到新的 RSA,同时使您的加密函数变得纯净并放弃不必要的比较。我们最终得到:

import Criterion.Main
import Criterion.Config
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Codec.Crypto.RSA
import Crypto.Random.DRBG

main :: IO ()
main = do
  r1 <- newGenIO :: IO HashDRBG
  r2 <- newGenIO :: IO (GenBuffered HashDRBG)

  -- We don't care about the performance of generate, so we do it outside the benchmark framework
  let (pub,priv,g2) = generateKeyPair r2 1024

  defaultMainWith defaultConfig (return ()) [
    bgroup "RSA" [
       bench "1" $ whnf (enc r1 pub priv) m1
       , bench "2" $ whnf (enc r2 pub priv) m1
     ]
   ]

m1 :: L.ByteString
m1 = L.pack [0..63]

enc :: CryptoRandomGen g => g -> PublicKey -> PrivateKey -> L.ByteString -> L.ByteString
enc g pub priv m = 
    let (em,ng) = encrypt g pub m
        dm     = decrypt   priv em 
    in dm

这会产生大约 3.5 毫秒的测量结果(使用 GHC 7.4 和 -O2 编译)。需要明确的是:我并不是说 RSA 比 OpenSSL 更快——OpenSSL 测试有更多的开销(加载可执行文件、读取密钥、读取明文、加密、写入结果),而且它非常可信地可能是一个命令比 RSA 包快很多。我的意思是“嘿,看,Haskell RSA 代码的执行速度非常快,我根本不在乎,如果你愿意,你可以进一步完善基准测试。”

作为参考,openssl speed rsa1024 说它在 0.5 毫秒内签名(显然是在我的机器上),我怀疑这是 16 字节的 RSA 加密以及其他操作。

【讨论】:

    【解决方案2】:

    简短的回答是我不知道,我没有什么可比较的。我试图找出如何使 openssl 执行相同的操作,但没有找到任何可以理解的(我)文档。所以我所能做的就是玩弄 Haskell RSA 代码(顺便说一句,你的代码不适用于最新版本的 hackage,相关约束现在是 CryptoRandomGen 而不是 RandomGen,所以我捏造了一个 @987654324 @,当然不是最理想的,但这并没有太大的区别)。

    我玩弄的结论是,Haskell RSA 的实现肯定是可以改进的,但可能不会太慢​​。它的速度是否可以接受当然取决于您的需求。

    起点是您的基准代码与我捏造的CryptoRandomGen 实例。在我的计算机上报告的 8K 字符串平均值约为 360 毫秒(64 位 linux,Core i5 M2410,2.3GHz)。

    将密钥生成移出基准测试可以将时间缩短到约 295 毫秒,因此密钥生成相当重要,主要是由于次优的质数测试。强 Fermat 检验的更好实现可以大大减少质数发现时间,而使用 Baillie PSW 检验代替 Miller-Rabin 可以进一步缩短。

    在密钥生成之外,缺少模幂实现,它在指数上使用一位移位,这对于大型Integers 来说相当慢。改进后会显着减少运行时间,但不会显着减少。

    我可以稍微提高性能的另一点是八位字节流和Integers 之间的转换,但与上述相比差异很小。

    完成了明显的事情后,剩下的就是找出时间花在哪里了。事实证明,绝大多数时间都花在了模幂运算上。幸运的是,单独对模幂算法进行基准测试并将其与 GMP 的性能进行比较相对容易。一个快速而肮脏的测试表明(至少在我的计算机上)GMP 的 mpz_powm 的工作速度大约是我的 Haskell 实现的 2-2.5 倍(因此,如果 GHC 提供了与 mpz_powm 的直接绑定,那么主要的加速可能是预期)。

    总而言之,8K 基准测试现在在约 270 毫秒(包括密钥生成)和约 245 毫秒(不包括密钥生成)中运行,其中大约 200 毫秒用于模幂运算。

    假设大小限制不允许显着优于 GMP 的模幂运算,我估计一个好的 C 实现将是当前 RSA 包¹的 5-10 倍。

    这可以接受吗?您的来电。

    ¹但我有一半认为会因一个不平凡的因素而偏离。

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 2012-11-10
      • 1970-01-01
      • 1970-01-01
      • 2017-02-16
      • 2020-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多