crypto / rand的典型用法是这样的:
salt := make([]byte, saltLength)
n,err := rand.Read(salt)
填充我标记的字节切片" salt"这里有一系列随机字节。
在什么情况下随机数发生器会失败?如果错误不是零,那么回到数学/兰特等值是否不安全?
由于字节切片的长度已经知道,n对我来说似乎也没用,是否有任何理由我不会使用_,错误代替它?
答案 0 :(得分: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
附录:
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 interface { Read(p []byte) (n int, err error) }
Reader是包装基本Read方法的接口。
读取读取最多len(p)个字节到p。它返回字节数 读取(0< = n< = len(p))并遇到任何错误。即使阅读 返回n< len(p),它可以使用所有p作为临时空间 呼叫。如果某些数据可用但不是len(p)字节,则读取 通常会返回可用的内容,而不是等待更多内容。
Read之后遇到错误或文件结束条件 成功阅读n> 0字节,它返回读取的字节数。 它可能会从同一个调用返回(非零)错误或返回 来自后续调用的错误(和n == 0)。这个将军的一个例子 case是一个Reader在结尾返回非零字节数 输入流可以返回err == EOF或err == nil。该 next Read应返回0,EOF无论如何。
来电者应始终处理n>之前返回0个字节 考虑到错误错误。这样做可以正确处理I / O错误 在读取一些字节以及两个允许的EOF之后发生 的行为。
不鼓励读取的实现返回零字节 以零错误计数,并且呼叫者应将该情况视为一个 无操作。
我们只想在启动Read
循环之前分配缓冲区一次。但是,我们希望编译器和运行时检测我们是否偏离n
循环中的有效缓冲区长度Read
,因此我们编写buf = buf[:n]
。但是,当我们循环到下一个Read
时,我们明确地需要完整的缓冲区:buf[:cap(buf)
。
写Read(buf[:cap(buf)])
永远不会错。即使您现在可能没有Read
循环,也可以稍后添加一个循环,但您可能忘记重置缓冲区长度。特定Read
实现可能有特殊情况,例如基础ReadFull
。现在,您必须阅读并监视底层代码,以证明您的代码是正确的。文档并不总是可靠的。并且您无法安全地切换到另一个io.Reader
Read
实施。
当您访问salt
切片salt[:len(salt)]
时,您使用的是len(salt)
而不是n
。如果它们不同,那你就有一个错误。
“实现应遵循健壮性的一般原则:be 在你所做的事情上保守,在你接受的事上保持自由 其他人。“Jon Postel