Skip to content

Commit

Permalink
allow for custom RNGs and for isolation of istances of Cryptipass
Browse files Browse the repository at this point in the history
  • Loading branch information
Aizen committed Oct 5, 2024
1 parent 3abf992 commit 0409c62
Show file tree
Hide file tree
Showing 5 changed files with 484 additions and 471 deletions.
6 changes: 4 additions & 2 deletions cmd/genpw/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Passphrase struct {
}

func main() {
g := cp.NewInstance()
cert := flag.Bool("c", false, "run entropy certification algorithm\nusers not necessarily need to concern with this detail.")
depth := flag.Uint64("cd", 1, "certification effort.\nA larger number leads to more accurate results\nat the expense of exponentially longer completion times.")
f_pattern := flag.String("p", "W.w.w",
Expand All @@ -38,7 +39,7 @@ func main() {

pws := []Passphrase{}
for range *passwords {
F, H := cp.GenFromPattern(pattern)
F, H := g.GenFromPattern(pattern)
pws = append(pws, Passphrase{F: F, H: H})
}
slices.SortFunc(pws, func(a, b Passphrase) int {
Expand Down Expand Up @@ -66,6 +67,7 @@ func main() {
}

func certify(pattern string, udepth uint64) {
g := cp.NewInstance()
cnt := make(map[string]int)
iN := 0
Q := 128
Expand All @@ -75,7 +77,7 @@ func certify(pattern string, udepth uint64) {
for {
Q += Q / 14
for range Q {
w, nh := cp.GenFromPattern(pattern)
w, nh := g.GenFromPattern(pattern)
nominal_H += nh
nominal_H2 += nh * nh
cnt_nom_H++
Expand Down
35 changes: 20 additions & 15 deletions cryptipass.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,23 @@ import (
"strings"
)

var rng *rand.Rand
type Generator struct {
Rng *rand.Rand
}

// init initializes the cryptographically secure random number generator (RNG).
// NewInstance initializes the cryptographically secure random number generator (RNG).
// It reads 32 bytes of entropy from crypto/rand and uses them to seed a ChaCha8-based RNG.
// If the required number of bytes is not read, it logs a fatal error.
func init() {
func NewInstance() *Generator {
seed := [32]byte{}
n, err := cr.Reader.Read(seed[:])
if err != nil || n != 32 {
log.Fatal(n, err, seed)
}
rng = rand.New(rand.NewChaCha8(seed))
rng := rand.New(rand.NewChaCha8(seed))
g := new(Generator)
g.Rng = rng
return g
}

// NewPassphrase generates a passphrase consisting of the specified number of random words.
Expand All @@ -38,11 +43,11 @@ func init() {
// string: The generated passphrase, with words joined by periods.
//
// float64: The total entropy (in bits) of the passphrase, indicating its strength.
func GenPassphrase(words uint64) (string, float64) {
func (g *Generator) GenPassphrase(words uint64) (string, float64) {
wordvec := []string{}
total_entropy := 0.0
for range words {
tok, h := GenFromPattern("w")
tok, h := g.GenFromPattern("w")
wordvec = append(wordvec, tok)
total_entropy += h
}
Expand Down Expand Up @@ -73,7 +78,7 @@ func GenPassphrase(words uint64) (string, float64) {
//
// float64: The total entropy (in bits) of the generated passphrase.

func GenFromPattern(pattern string) (string, float64) {
func (g *Generator) GenFromPattern(pattern string) (string, float64) {
passphrase := ""
entropy := 0.0
pushnext := false
Expand All @@ -88,22 +93,22 @@ func GenFromPattern(pattern string) (string, float64) {
pushnext = true
continue
case 'w', 'W':
head, h_head := GenWord(c)
head, h_head := g.GenWord(c)
passphrase = passphrase + head
entropy = entropy + h_head
case 'd':
d := rng.IntN(10)
d := g.Rng.IntN(10)
H := math.Log2(10.0)
passphrase += fmt.Sprint(d)
entropy += H
case 's':
symbols := "@#!$%&=?^+-*\""
d := rng.IntN(len(symbols))
d := g.Rng.IntN(len(symbols))
H := math.Log2(float64(len(symbols)))
passphrase += string(symbols[d])
entropy += H
case 'c', 'C':
runc, dH := PickNext(strings.ToLower(passphrase))
runc, dH := g.PickNext(strings.ToLower(passphrase))
if c == 'C' {
runc = strings.ToUpper(runc)
}
Expand All @@ -117,14 +122,14 @@ func GenFromPattern(pattern string) (string, float64) {
return passphrase, entropy
}

func GenWord(c rune) (string, float64) {
head, h_head := PickNext("")
leng, h_leng := PickLength()
func (g *Generator) GenWord(c rune) (string, float64) {
head, h_head := g.PickNext("")
leng, h_leng := g.PickLength()
if c == 'W' {
head = strings.ToUpper(head)
}
for len(head) < leng {
c, h := PickNext(strings.ToLower(head))
c, h := g.PickNext(strings.ToLower(head))
head += c
h_head += h
}
Expand Down
18 changes: 12 additions & 6 deletions cryptipass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

func TestBasic(t *testing.T) {
pw, H := cryptipass.GenPassphrase(4)
g := cryptipass.NewInstance()
pw, H := g.GenPassphrase(4)
if len(pw) < 15 {
t.Fatalf(`Wrong length "%s"`, pw)
}
Expand All @@ -20,8 +21,9 @@ func TestBasic(t *testing.T) {

// TestGenPassphrase tests the GenPassphrase function for generating a passphrase and validating its length.
func TestGenPassphrase(t *testing.T) {
g := cryptipass.NewInstance()
words := uint64(5)
passphrase, entropy := cryptipass.GenPassphrase(words)
passphrase, entropy := g.GenPassphrase(words)
wordList := strings.Split(passphrase, ".")

if len(wordList) != int(words) {
Expand All @@ -35,7 +37,8 @@ func TestGenPassphrase(t *testing.T) {

// TestGenWord tests that GenWord generates a word and returns a positive entropy value.
func TestGenWord(t *testing.T) {
word, entropy := cryptipass.GenWord('W')
g := cryptipass.NewInstance()
word, entropy := g.GenWord('W')

if len(word) == 0 {
t.Error("Expected a word, got an empty string")
Expand All @@ -48,8 +51,9 @@ func TestGenWord(t *testing.T) {

// TestPickNext tests that PickNext generates a valid character appended to the seed and returns entropy.
func TestPickNext(t *testing.T) {
g := cryptipass.NewInstance()
seed := "te"
next, entropy := cryptipass.PickNext(seed)
next, entropy := g.PickNext(seed)
if len(next) != 1 {
t.Errorf("Expected string extension to be 1 rune long")
}
Expand All @@ -61,7 +65,8 @@ func TestPickNext(t *testing.T) {

// TestPickLength tests that PickLength generates a valid word length and returns entropy.
func TestPickLength(t *testing.T) {
length, entropy := cryptipass.PickLength()
g := cryptipass.NewInstance()
length, entropy := g.PickLength()

if length < 3 || length > 9 {
t.Errorf("Expected length to be between 3 and 9, got %d", length)
Expand All @@ -74,8 +79,9 @@ func TestPickLength(t *testing.T) {

// TestGenFromPattern tests that GenFromPattern generates a word of a specific length and returns a positive entropy value.
func TestGenFromPattern(t *testing.T) {
g := cryptipass.NewInstance()
pattern := "Cccc.cccc@dd"
word, entropy := cryptipass.GenFromPattern(pattern)
word, entropy := g.GenFromPattern(pattern)

if len(word) != len(pattern) {
t.Errorf("Expected word length %d, got %d", len(pattern), len(word))
Expand Down
8 changes: 4 additions & 4 deletions dev/distill.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function makesampler(io, rawV)
H -= log2(c / nor) * c / nor
end
println(io, sep^2, "H := ", H)
println(io, sep^2, "r := rng.IntN(", sum(C), ")")
println(io, sep^2, "r := g.Rng.IntN(", sum(C), ")")
println(io, sep^2, "switch {")
cum = 0
for (s, c) in zip(S, C)
Expand Down Expand Up @@ -58,7 +58,7 @@ function whole_sampler(data)
// string: The updated string after appending the next character.
// float64: The entropy contributed by the character selection process."""
)
println(io, "func PickNext(seed string) (string, float64) {")
println(io, "func (g *Generator) PickNext(seed string) (string, float64) {")
println(io, sep, "L := min(len(seed),2)")
println(io, sep, "tok := strings.ToLower(seed[len(seed)-L:])")
println(io, sep, "retry:")
Expand Down Expand Up @@ -102,8 +102,8 @@ function makegensampler(rawV)
)
cum = 0
ifs = "if"
println(io, "func PickLength() (int, float64) {")
println(io, " ", "r := rng.IntN(", sum(C), ")")
println(io, "func (g *Generator) PickLength() (int, float64) {")
println(io, " ", "r := g.Rng.IntN(", sum(C), ")")
println(io, " ", "H := ", H)
for (s, c) in zip(S, C)
println(io, " ", ifs, " r < ", cum + c, " {\n return ", s, ", H")
Expand Down
Loading

0 comments on commit 0409c62

Please sign in to comment.