2014-10-26 111 views
-1

加密/兰特的典型用法是这样的:在什么情况下,crypto/rand read()的返回值会有用吗?

salt := make([]byte, saltLength) 
n,err := rand.Read(salt) 

与随机字节序列这里填充字节片我都标有“盐”。

在什么情况下随机数生成器会失败?在err不是零的情况下,回到数学/兰德等价物会不安全吗?

由于字节片段的长度已经知道,n对我来说也似乎没用,是不是有什么理由我不会只用_,err代替它?

+0

如果没有足够的熵可用于生成“随机”(无论是什么意思)数量。 – Volker 2014-10-26 21:03:36

回答

2

为了安全起见你的代码看起来更像是这样的:

package main 

import (
    "crypto/rand" 
    "fmt" 
) 

func main() { 
    saltLength := 16 
    salt := make([]byte, saltLength) 
    n, err := rand.Read(salt[:cap(salt)]) 
    if err != nil { 
     // handle error 
    } 
    salt = salt[:n] 
    if len(salt) != saltLength { 
     // handle error 
    } 
    fmt.Println(len(salt), salt) 
} 

输出:

16 [191 235 81 37 175 238 93 202 230 158 41 199 202 85 67 209] 

n可能小于len(salt)如果熵不足是可用的。你应该经常检查错误。

例如,获得一系列随机数的众多方法之一是Linux上的getrandom系统调用或Windows上的CryptGenRandom API调用。

参考文献:

random: introduce getrandom(2) system call

CryptGenRandom function

附录:

crypto/rand包是密码安全伪随机数发生器。包math/rand不是加密安全的。

即使是一个简单的程序中也有太多路径来测试它们。因此,编写零缺陷和零错误程序的唯一方法是编写可读,可维护的代码,这些代码是非常正确的。 Niklaus Wirth的系统编程是一个很好的入门书。花时间构建一个强大的通用表单非常值得,它可以很容易地适应每种特殊情况,并且随着需求的变化很容易维护。

例如,对于io.Reader接口,典型用法是循环模式。

func Reader(rdr io.Reader) error { 
    bufLen := 256 
    buf := make([]byte, bufLen) 
    for { 
     n, err := rdr.Read(buf[:cap(buf)]) 
     if n == 0 { 
      if err == nil { 
       continue 
      } 
      if err == io.EOF { 
       break 
      } 
      return err 
     } 
     buf = buf[:n] 
     // process read buffer 
     if err != nil && err != io.EOF { 
      return err 
     } 
    } 
    return nil 
} 

type Reader

type Reader interface { 
     Read(p []byte) (n int, err error) 
} 

Reader是一个包装的基本Read方法的接口。

读取最多len(p)个字节到p。它返回读取的字节数 (0 < = n < = len(p))以及遇到的任何错误。即使读取 返回len(p),它可能会在调用 期间将所有p用作暂存空间。如果有些数据可用但不是len(p)字节,则通常返回可用的数据,而不是等待更多数据。

当 成功读取n> 0字节后,如果读取遇到错误或文件结束条件,它将返回读取的字节数。 它可能会从相同的调用中返回(非零)错误,或者返回后续调用中的 错误(和n == 0)。这种通用 情况的一个实例是,在输入流的末尾 处返回非零字节数的Reader可以返回err == EOF或err == nil。接下来的 应该返回0,EOF不管。

考虑到错误错误,调用者应始终处理在 之前返回的n> 0个字节。这样做可以正确处理在读取一些字节以及允许的EOF 行为之后发生的 发生的I/O错误。

不推荐使用Read的实现返回一个零字节 计数为零的错误,并且调用者应该将该情况视为 禁止操作。

我们只想分配一次缓冲区,然后再启动Read循环。但是,我们希望编译器和运行时检测是否我们在Read循环中超出有效缓冲区长度n,因此我们编写buf = buf[:n]。但是,当我们循环到下一个Read时,我们明确需要完整缓冲区:buf[:cap(buf)

编写Read(buf[:cap(buf)])绝对不会错。即使您现在可能没有Read循环,您可能稍后再添加一个循环,但您可能会忘记重置缓冲区长度。对于特定的Read实施可能有特殊情况,如底层ReadFull。现在您必须阅读并监视底层代码,以证明您的代码是正确的。文件并不总是可靠的。并且您不能安全地切换到另一个io.ReaderRead实施。

当您访问salt切片时,salt[:len(salt)],您使用的是len(salt)而不是n。如果他们不同,你有一个错误。

“的实施应遵循稳健性的一般原则:是 保守你做什么,是你从 别人接受什么样的自由。” Jon Postel

+0

@ 4of4:不正确。这是防弹代码。 – peterSO 2014-10-26 22:02:06

+0

太棒了!谢谢!那么我是否假设使用数学/兰德作为后备,如果加密/兰德失败将不安全?你能解释一下你为什么要做'salt = salt [:n]'为什么不把saltLength和n比较? – jcmiller11 2014-10-27 13:17:28

+0

@ jcmiller11:查看我答案的附录。 – peterSO 2014-10-27 15:29:26

相关问题