源文本,Go中加密/解密的密钥大小关系

时间:2015-06-01 15:39:46

标签: encryption go cryptography aes rsa

在下面的代码中(同样在http://play.golang.org/p/77fRvrDa4A但在浏览器中“处理时间太长”) sourceText 的124字节版本将不会加密,因为:“message对于RSA公钥大小“1024,它太长了。它和更长的124字节 sourceText 版本,使用2048位密钥大小。

我的问题是,如果给出源文本的字节长度,如何精确计算 rsa.GenerateKey 中的密钥大小? (在4096密钥大小的情况下,一小段文本大小需要10秒钟,直到运行时我才知道sourceText的长度。)

https://stackoverflow.com/a/11750658/3691075对此有一个非常简短的讨论,但我不清楚,因为我不是一个加密的家伙。

我的目标是加密,存储在数据库中并解密大约300字节长的JSON字符串。我控制发送端和接收端。文本加密一次,并多次解密。任何战略提示都将受到赞赏。

package main

import (
    "crypto/md5"
    "crypto/rand"
    "crypto/rsa"
    "fmt"
    "hash"
    "log"
    "time"
)

func main() {
     startingTime := time.Now()
     var err error
     var privateKey *rsa.PrivateKey
     var publicKey *rsa.PublicKey
     var sourceText, encryptedText, decryptedText, label []byte

    // SHORT TEXT 92 bytes
     sourceText = []byte(`{347,7,3,8,7,0,7,5,6,4,1,6,5,6,7,3,7,7,7,6,5,3,5,3,3,5,4,3,2,10,3,7,5,6,65,350914,760415,33}`)
     fmt.Printf("\nsourceText byte length:\n%d\n", len(sourceText))

    // LONGER TEXT 124 bytes
    // sourceText = []byte(`{347,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,65,350914,760415,33}`)
    // fmt.Printf("\nsourceText byte length:\n%d\n", len(sourceText))

    if privateKey, err = rsa.GenerateKey(rand.Reader, 1024); err != nil {
         log.Fatal(err)
    }

    // fmt.Printf("\nprivateKey:\n%s\n", privateKey)

    privateKey.Precompute()

    if err = privateKey.Validate(); err != nil {
         log.Fatal(err)
    }

     publicKey = &privateKey.PublicKey

     encryptedText = encrypt(publicKey, sourceText, label)
     decryptedText = decrypt(privateKey, encryptedText, label)

     fmt.Printf("\nsourceText: \n%s\n", string(sourceText))
     fmt.Printf("\nencryptedText: \n%x\n", encryptedText)
     fmt.Printf("\ndecryptedText: \n%s\n", decryptedText)

     fmt.Printf("\nDone in %v.\n\n", time.Now().Sub(startingTime))
}

func encrypt(publicKey *rsa.PublicKey, sourceText, label []byte) (encryptedText []byte) {
     var err error
     var md5_hash hash.Hash
     md5_hash = md5.New()
     if encryptedText, err = rsa.EncryptOAEP(md5_hash, rand.Reader,           publicKey, sourceText, label); err != nil {
         log.Fatal(err)
     }
     return
}

func decrypt(privateKey *rsa.PrivateKey, encryptedText, label []byte) (decryptedText []byte) {
     var err error
     var md5_hash hash.Hash
     md5_hash = md5.New()
     if decryptedText, err = rsa.DecryptOAEP(md5_hash, rand.Reader, privateKey, encryptedText, label); err != nil {
         log.Fatal(err)
     }
     return
}

1 个答案:

答案 0 :(得分:4)

通常不会根据有效负载计算RSA密钥大小。一个人只需根据安全性(越大越好)和性能(越小越好)之间的折衷选择一个RSA密钥大小。如果这样做,请将hybrid encryption与AES或其他对称密码结合使用,以实际加密数据。

如果有效负载不超过300字节并且您正在使用OAEP(至少42字节的填充),那么您可以轻松计算最小密钥大小:

(300 + 42) * 8 = 2736 bit

这已经是一个合理的大小键。它根据今天的规范提供了良好的安全性,而且速度相当快。没有必要为此应用混合加密方案。

现在,您可能会注意到密钥大小不是2. This is not a problem的幂。但是,您应该使用64位倍数的密钥大小,因为处理器使用32位和64位基元来进行实际计算,因此您可以在不降低性能的情况下提高安全性。下一个这样的密钥大小将是:

ceil((300 + 42) * 8 / 64.0) * 64 = 2752 bit

以下是一些实验结果,一些语言/框架接受(不是性能)作为密钥大小:

  • Golang:1位的倍数和> = 1001(原文如此!)[used ideone.com]
  • PyCrypto:256位的倍数,> = 1024 [本地安装]
  • C#:16位的倍数和> = 512 [使用ideone.com]
  • Groovy:1位的倍数,> = 512 [本地安装]
  • Java:1位的倍数和> = 512 [使用ideone.com:Java& Java7]
  • PHP / OpenSSL Ext:128位和> = 640的倍数[使用ideone.com]
  • 加密++:多个1位且> = 16 [本地安装,最大验证韧性为3]

在决定使用某种特定密钥大小之前,应检查所有框架是否支持该大小。如你所见,结果差异很大。

我尝试用不同的密钥大小编写密钥生成,加密和解密的一些性能测试:512,513,514,516,520,528,544,576。因为我不知道任何去,它很难让时机成熟。所以我选择了Java和Crypto ++。 Crypto ++代码可能非常错误,因为520位和528位密钥的密钥生成速度比其他密钥大小快7个数量级,而其他密钥大小对于小密钥大小窗口或多或少是恒定的。

在Java中,密钥生成非常清楚,因为513位密钥的生成比<512>密钥慢2-3 。除此之外,结果几乎是线性的。对于完整的keygen-enc-dec循环,该图被归一化并且迭代次数为1000。

key generation, encryption and decryption performance for different key sizes

解密在544位稍微下降,这是32位的倍数。由于它是在32位debian上执行的,这可能意味着确实有一些性能改进,但另一方面,加密对于该密钥大小来说速度较慢。

由于这个基准测试没有在Go中完成,我不会就开销有多小提出任何建议。