Initial
This commit is contained in:
commit
8889eccef6
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/.idea
|
||||||
|
/passgen
|
10
dictionary/sets/ascii_lowercase.go
Normal file
10
dictionary/sets/ascii_lowercase.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func AsciiLowercase() (dict []int) {
|
||||||
|
// Print lowercase letters (ASCII 97 to 122)
|
||||||
|
for i := 97; i <= 122; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
10
dictionary/sets/ascii_uppercase.go
Normal file
10
dictionary/sets/ascii_uppercase.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func AsciiUppercase() (dict []int) {
|
||||||
|
// Print uppercase letters (ASCII 65 to 90)
|
||||||
|
for i := 65; i <= 90; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
50
dictionary/sets/chinese.go
Normal file
50
dictionary/sets/chinese.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func Chinese() (dict []int) {
|
||||||
|
// CJK Unified Ideographs (Common)
|
||||||
|
for i := 0x4E00; i <= 0x9FFF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension A (Rare)
|
||||||
|
for i := 0x3400; i <= 0x4DBF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension B (Rare, historic)
|
||||||
|
for i := 0x20000; i <= 0x2A6DF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension C (Rare, historic)
|
||||||
|
for i := 0x2A700; i <= 0x2B73F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension D (Uncommon, some in current use)
|
||||||
|
for i := 0x2B740; i <= 0x2B81F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension E (Rare, historic)
|
||||||
|
for i := 0x2B820; i <= 0x2CEAF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension F (Rare, historic)
|
||||||
|
for i := 0x2CEB0; i <= 0x2EBEF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension G (Rare, historic)
|
||||||
|
for i := 0x30000; i <= 0x3134F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK Unified Ideographs Extension H (Rare, historic)
|
||||||
|
for i := 0x31350; i <= 0x323AF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
37
dictionary/sets/cyrillic.go
Normal file
37
dictionary/sets/cyrillic.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func Cyrillic() (dict []int) {
|
||||||
|
// Cyrillic: U+0400–U+04FF (256 characters)
|
||||||
|
for i := 0x0400; i <= 0x04FF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyrillic Supplement: U+0500–U+052F (48 characters)
|
||||||
|
for i := 0x0500; i <= 0x052F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyrillic Extended-A: U+2DE0–U+2DFF (32 characters)
|
||||||
|
for i := 0x2DE0; i <= 0x2DFF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyrillic Extended-B: U+A640–U+A69F (96 characters)
|
||||||
|
for i := 0xA640; i <= 0xA69F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyrillic Extended-C: U+1C80–U+1C8F (9 characters)
|
||||||
|
for i := 0x1C80; i <= 0x1C8F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cyrillic Extended-D: U+1E030–U+1E08F (63 characters)
|
||||||
|
for i := 0x1E030; i <= 0x1E08F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
dict = append(dict, []int{0x1D2B, 0x1D78}...)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
30
dictionary/sets/japanese.go
Normal file
30
dictionary/sets/japanese.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func Japanese() (dict []int) {
|
||||||
|
// Japanese-style punctuation
|
||||||
|
for i := 0x3000; i <= 0x303F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hiragana
|
||||||
|
for i := 0x3040; i <= 0x309F; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Katakana
|
||||||
|
for i := 0x30A0; i <= 0x30FF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full-width roman characters and half-width katakana
|
||||||
|
for i := 0xFF00; i <= 0xFFEF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CJK unified ideographs (common and uncommon kanji)
|
||||||
|
for i := 0x4E00; i <= 0x9FAF; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
10
dictionary/sets/numbers.go
Normal file
10
dictionary/sets/numbers.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func Numbers() (dict []int) {
|
||||||
|
// Print numbers (ASCII 48 to 57)
|
||||||
|
for i := 48; i <= 57; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
7
dictionary/sets/space.go
Normal file
7
dictionary/sets/space.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func Space() (dict []int) {
|
||||||
|
dict = append(dict, ' ')
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
10
dictionary/sets/special_chars.go
Normal file
10
dictionary/sets/special_chars.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func SpecialChars() (dict []int) {
|
||||||
|
// Print special symbols (ASCII 33 to 47)
|
||||||
|
for i := 33; i <= 47; i++ {
|
||||||
|
dict = append(dict, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
14
dictionary/shuffle.go
Normal file
14
dictionary/shuffle.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package dictionary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ShuffleDictionarySet(slice []int) []int {
|
||||||
|
for i := len(slice) - 1; i > 0; i-- {
|
||||||
|
j := rand.IntN(i + 1)
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice
|
||||||
|
}
|
48
generator.go
Normal file
48
generator.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "math/rand/v2"
|
||||||
|
|
||||||
|
func generatePassword(sets [][]int, passwordLength int) []int {
|
||||||
|
numSets := len(sets)
|
||||||
|
totalLength := 0
|
||||||
|
for _, set := range sets {
|
||||||
|
totalLength += len(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
props := make([]float64, numSets)
|
||||||
|
for i := range props {
|
||||||
|
props[i] = float64(len(sets[i])) / float64(totalLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
numChars := make([]int, numSets)
|
||||||
|
for i := range numChars {
|
||||||
|
numChars[i] = int(props[i] * float64(passwordLength))
|
||||||
|
if numChars[i] == 0 {
|
||||||
|
numChars[i] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalChars := 0
|
||||||
|
for _, n := range numChars {
|
||||||
|
totalChars += n
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalChars < passwordLength {
|
||||||
|
numChars[0]++
|
||||||
|
} else if totalChars > passwordLength {
|
||||||
|
numChars[numSets-1]--
|
||||||
|
}
|
||||||
|
|
||||||
|
password := make([]int, 0, passwordLength)
|
||||||
|
for i, set := range sets {
|
||||||
|
for j := 0; j < numChars[i]; j++ {
|
||||||
|
password = append(password, set[rand.IntN(len(set))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Shuffle(len(password), func(i, j int) {
|
||||||
|
password[i], password[j] = password[j], password[i]
|
||||||
|
})
|
||||||
|
|
||||||
|
return password
|
||||||
|
}
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module gitea.stuzer.link/stuzer05/passgen
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require golang.org/x/text v0.9.0 // indirect
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
91
main.go
Normal file
91
main.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"gitea.stuzer.link/stuzer05/passgen/dictionary"
|
||||||
|
"gitea.stuzer.link/stuzer05/passgen/dictionary/sets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// password flags
|
||||||
|
flagLen := flag.Int("L", 16, "length of the generated password")
|
||||||
|
flagCount := flag.Int("c", 1, "how many passwords to generate")
|
||||||
|
|
||||||
|
// set flags
|
||||||
|
flagSetAll := flag.Bool("all", false, "use all character sets")
|
||||||
|
flagSetAsciiLowercase := flag.Bool("l", false, "use lowercase ascii characters")
|
||||||
|
flagSetAsciiUppercase := flag.Bool("U", false, "use uppercase ascii characters")
|
||||||
|
flagSetNumbers := flag.Bool("n", false, "use numbers")
|
||||||
|
flagSetSpecialChars := flag.Bool("s", false, "use special characters")
|
||||||
|
flagSetSpaces := flag.Bool("S", false, "use spaces")
|
||||||
|
flagSetUnicodeJapanese := flag.Bool("unicode-japanese", false, "use unicode Japanese characters")
|
||||||
|
flagSetUnicodeChinese := flag.Bool("unicode-chinese", false, "use unicode Chinese characters")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// check password length
|
||||||
|
if *flagLen <= 0 {
|
||||||
|
fmt.Println("password length must be at least 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check password count
|
||||||
|
if *flagCount <= 0 {
|
||||||
|
fmt.Println("passwords count must be at least 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// use all character sets
|
||||||
|
if *flagSetAll {
|
||||||
|
*flagSetAsciiLowercase = true
|
||||||
|
*flagSetAsciiUppercase = true
|
||||||
|
*flagSetNumbers = true
|
||||||
|
*flagSetSpecialChars = true
|
||||||
|
*flagSetSpaces = true
|
||||||
|
|
||||||
|
*flagSetUnicodeJapanese = true
|
||||||
|
*flagSetUnicodeChinese = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// use default password preset no sets were requested
|
||||||
|
if !*flagSetAll && !*flagSetAsciiLowercase && !*flagSetAsciiUppercase && !*flagSetNumbers && !*flagSetSpecialChars && !*flagSetSpaces && !*flagSetUnicodeJapanese && !*flagSetUnicodeChinese {
|
||||||
|
*flagSetAsciiLowercase = true
|
||||||
|
*flagSetAsciiUppercase = true
|
||||||
|
*flagSetNumbers = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// select dictionaries
|
||||||
|
var characterSets [][]int
|
||||||
|
|
||||||
|
if *flagSetAsciiLowercase {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.AsciiLowercase()))
|
||||||
|
}
|
||||||
|
if *flagSetAsciiUppercase {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.AsciiUppercase()))
|
||||||
|
}
|
||||||
|
if *flagSetNumbers {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Numbers()))
|
||||||
|
}
|
||||||
|
if *flagSetSpecialChars {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.SpecialChars()))
|
||||||
|
}
|
||||||
|
if *flagSetSpaces {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Space()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unicode
|
||||||
|
if *flagSetUnicodeJapanese {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Japanese()))
|
||||||
|
}
|
||||||
|
if *flagSetUnicodeChinese {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Chinese()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate passwords
|
||||||
|
for i := 0; i < *flagCount; i++ {
|
||||||
|
password := generatePassword(characterSets, *flagLen)
|
||||||
|
|
||||||
|
for _, i := range password {
|
||||||
|
fmt.Printf("%c", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user