Adding upstream version 1.0.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
25c29c6190
commit
cd7c72beb5
20 changed files with 1539 additions and 0 deletions
109
random.go
Normal file
109
random.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
)
|
||||
|
||||
// idLen is a length of captcha id string.
|
||||
// (20 bytes of 62-letter alphabet give ~119 bits.)
|
||||
const idLen = 20
|
||||
|
||||
// idChars are characters allowed in captcha id.
|
||||
var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
// rngKey is a secret key used to deterministically derive seeds for
|
||||
// PRNGs used in image. Generated once during initialization.
|
||||
var rngKey [32]byte
|
||||
|
||||
func init() {
|
||||
if _, err := io.ReadFull(rand.Reader, rngKey[:]); err != nil {
|
||||
panic("captcha: error reading random source: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Purposes for seed derivation. The goal is to make deterministic PRNG produce
|
||||
// different outputs for images and audio by using different derived seeds.
|
||||
const (
|
||||
imageSeedPurpose = 0x01
|
||||
audioSeedPurpose = 0x02
|
||||
)
|
||||
|
||||
// deriveSeed returns a 16-byte PRNG seed from rngKey, purpose, id and digits.
|
||||
// Same purpose, id and digits will result in the same derived seed for this
|
||||
// instance of running application.
|
||||
//
|
||||
// out = HMAC(rngKey, purpose || id || 0x00 || digits)
|
||||
func deriveSeed(purpose byte, id string, digits []byte) (out [32]byte) {
|
||||
var buf [sha256.Size]byte
|
||||
|
||||
h := hmac.New(sha256.New, rngKey[:])
|
||||
h.Write([]byte{purpose})
|
||||
h.Write([]byte(id))
|
||||
h.Write([]byte{0})
|
||||
h.Write(digits)
|
||||
|
||||
sum := h.Sum(buf[:0])
|
||||
copy(out[:], sum)
|
||||
return
|
||||
}
|
||||
|
||||
// RandomDigits returns a byte slice of the given length containing
|
||||
// pseudorandom numbers in range 0-9. The slice can be used as a captcha
|
||||
// solution.
|
||||
func RandomDigits(length int) []byte {
|
||||
return randomBytesMod(length, 10)
|
||||
}
|
||||
|
||||
// randomBytes returns a byte slice of the given length read from CSPRNG.
|
||||
func randomBytes(length int) (b []byte) {
|
||||
b = make([]byte, length)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
panic("captcha: error reading random source: " + err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// randomBytesMod returns a byte slice of the given length, where each byte is
|
||||
// a random number modulo mod.
|
||||
func randomBytesMod(length int, mod byte) (b []byte) {
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
if mod == 0 {
|
||||
panic("captcha: bad mod argument for randomBytesMod")
|
||||
}
|
||||
|
||||
maxrb := 255 - byte(256%int(mod))
|
||||
b = make([]byte, length)
|
||||
i := 0
|
||||
for {
|
||||
r := randomBytes(length + (length / 4))
|
||||
for _, c := range r {
|
||||
if c > maxrb {
|
||||
// Skip this number to avoid modulo bias.
|
||||
continue
|
||||
}
|
||||
b[i] = c % mod
|
||||
i++
|
||||
if i == length {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// randomID returns a new random id string.
|
||||
func randomID() string {
|
||||
b := randomBytesMod(idLen, byte(len(idChars)))
|
||||
for i, c := range b {
|
||||
b[i] = idChars[c]
|
||||
}
|
||||
return string(b)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue