specialpass/specialpass.go

195 lines
4.5 KiB
Go
Raw Normal View History

2013-07-27 01:37:36 -04:00
package main
import (
"code.google.com/p/gopass"
"flag"
"fmt"
"io"
"strings"
"crypto/sha512"
)
type PasswordRestrictions struct {
name string
minLength int
maxLength int
alphaLowerMin int
alphaLowerMax int
alphaUpperMin int
alphaUpperMax int
numberMin int
numberMax int
specialMin int
specialMax int
allowedSpecial string
}
var siteName string
const DEFAULT_SITE = "etrade"
var sites []PasswordRestrictions = []PasswordRestrictions{
PasswordRestrictions{
name: "etrade",
minLength: 6,
maxLength: 32,
alphaLowerMin: 0,
alphaLowerMax: 32,
alphaUpperMin: 0,
alphaUpperMax: 32,
numberMin: 1,
numberMax: 32,
specialMin: 0,
specialMax: 0},
PasswordRestrictions{
name: "fidelity",
minLength: 6,
maxLength: 12,
alphaLowerMin: 0,
alphaLowerMax: 12,
alphaUpperMin: 0,
alphaUpperMax: 12,
numberMin: 0,
numberMax: 12,
specialMin: 0,
specialMax: 0},
}
func init() {
const site_usage = "Name of site for which to generate password"
flag.StringVar(&siteName, "siteName", DEFAULT_SITE, site_usage)
flag.StringVar(&siteName, "s", DEFAULT_SITE, site_usage+" (shorthand)")
}
func main() {
flag.Parse()
var restrictions *PasswordRestrictions
for _, v := range sites {
if strings.ToLower(siteName) == strings.ToLower(v.name) {
restrictions = &v
break
}
}
if restrictions == nil {
fmt.Println("Error: Site name not recognized, please use one of the following:")
for _, v := range sites {
fmt.Println("\t" + v.name)
}
}
oldPassword, err := gopass.GetPass("Enter Password: ")
if err != nil {
panic(err)
}
c := make(chan int)
go generateBytes(c, oldPassword, restrictions.name)
maxValue := 62 /*alphanumeric*/ + len(restrictions.allowedSpecial)
curAlphaLower := 0
curAlphaUpper := 0
curNumber := 0
curSpecial := 0
password := ""
lower := "abcdefghijklmnopqrstuvwxyz"
upper := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
numbers := "0123456789"
//build up the initial string, making sure we don't go over the max allowed for each type
for length := 0; length < restrictions.maxLength; length++ {
val := <- c % maxValue
switch {
case val >= 0 && val < 26:
if curAlphaLower + 1 <= restrictions.alphaLowerMax {
password += lower[val:val+1]
curAlphaLower++
}
case val >= 26 && val < 52:
if curAlphaUpper + 1 <= restrictions.alphaUpperMax {
password += upper[val-26:val-25]
curAlphaUpper++
}
case val >= 52 && val < 62:
if curNumber + 1 <= restrictions.numberMax {
password += numbers[val-52:val-51]
curNumber++
}
default:
if curSpecial + 1 <= restrictions.specialMax {
password += restrictions.allowedSpecial[val-62:val-61]
curSpecial++
}
}
}
//now, make sure we meet the minimum requirements. If we don't, start replacing items in the password
for {
removed := true
switch {
case curAlphaLower < restrictions.alphaLowerMin:
val := <- c % 26
password += lower[val:val+1]
curAlphaLower++
case curAlphaUpper < restrictions.alphaUpperMin:
val := <- c % 26
password += upper[val:val+1]
curAlphaUpper++
case curNumber < restrictions.numberMin:
val := <- c % 10
password += numbers[val:val+1]
curNumber++
case curSpecial < restrictions.specialMin:
val := <- c % len(restrictions.allowedSpecial)
password += restrictions.allowedSpecial[val:val+1]
curSpecial++
default:
removed = false
}
if !removed {
break
}
removedChar := password[:1]
password = password[1:]
switch{
case strings.Contains(lower, removedChar):
curAlphaLower--
case strings.Contains(upper, removedChar):
curAlphaUpper--
case strings.Contains(numbers, removedChar):
curNumber--
case strings.Contains(restrictions.allowedSpecial, removedChar):
curSpecial--
default:
panic("Unknown character made its way into the password")
}
}
//finally, (pseudo-)randomize the password ordering, one element at a time
for i := 0; i < restrictions.maxLength; i++ {
position := (<- c % (restrictions.maxLength - i)) + i
password = password[position:position+1] + password[0:position] + password[position+1:restrictions.maxLength]
}
fmt.Println("Generated password for " + restrictions.name + ": " + password)
}
func generateBytes(c chan int, password string, siteName string) {
h := sha512.New()
io.WriteString(h, password + strings.ToLower(siteName))
hashBytes := h.Sum(nil)
for {
for _, b := range hashBytes {
c <- int(b)
}
h.Write(hashBytes)
hashBytes = h.Sum(nil)
}
}