151 lines
2.7 KiB
Go
151 lines
2.7 KiB
Go
package mp
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"golang.org/x/crypto/scrypt"
|
|
"runtime"
|
|
"sync"
|
|
)
|
|
|
|
type TemplateType int
|
|
|
|
const (
|
|
MaximumSecurityPassword TemplateType = iota
|
|
LongPassword
|
|
MediumPassword
|
|
BasicPassword
|
|
ShortPassword
|
|
PIN
|
|
Name
|
|
Phrase
|
|
)
|
|
|
|
const variant = "com.lyndir.masterpassword"
|
|
|
|
var (
|
|
typeMap = map[TemplateType][]string{
|
|
MaximumSecurityPassword: {
|
|
"anoxxxxxxxxxxxxxxxxx",
|
|
"axxxxxxxxxxxxxxxxxno",
|
|
},
|
|
LongPassword: {
|
|
"CvcvnoCvcvCvcv",
|
|
"CvcvCvcvnoCvcv",
|
|
"CvcvCvcvCvcvno",
|
|
"CvccnoCvcvCvcv",
|
|
"CvccCvcvnoCvcv",
|
|
"CvccCvcvCvcvno",
|
|
"CvcvnoCvccCvcv",
|
|
"CvcvCvccnoCvcv",
|
|
"CvcvCvccCvcvno",
|
|
"CvcvnoCvcvCvcc",
|
|
"CvcvCvcvnoCvcc",
|
|
"CvcvCvcvCvccno",
|
|
"CvccnoCvccCvcv",
|
|
"CvccCvccnoCvcv",
|
|
"CvccCvccCvcvno",
|
|
"CvcvnoCvccCvcc",
|
|
"CvcvCvccnoCvcc",
|
|
"CvcvCvccCvccno",
|
|
"CvccnoCvcvCvcc",
|
|
"CvccCvcvnoCvcc",
|
|
"CvccCvcvCvccno",
|
|
},
|
|
MediumPassword: {
|
|
"CvcnoCvc",
|
|
"CvcCvcno",
|
|
},
|
|
BasicPassword: {
|
|
"aaanaaan",
|
|
"aannaaan",
|
|
"aaannaaa",
|
|
},
|
|
ShortPassword: {
|
|
"Cvcn",
|
|
},
|
|
PIN: {
|
|
"nnnn",
|
|
},
|
|
Name: {
|
|
"cvccvcvcv",
|
|
},
|
|
Phrase: {
|
|
"cvcc cvc cvccvcv cvc",
|
|
"cvc cvccvcvcv cvcv",
|
|
"cv cvccv cvc cvcvccv",
|
|
},
|
|
}
|
|
charMap = map[rune]string{
|
|
'V': "AEIOU",
|
|
'C': "BCDFGHJKLMNPQRSTVWXYZ",
|
|
'v': "aeiou",
|
|
'c': "bcdfghjklmnpqrstvwxyz",
|
|
'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",
|
|
'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",
|
|
'n': "0123456789",
|
|
'o': "@&%?,=[]_:-+*$#!'^~;()/.",
|
|
'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",
|
|
' ': " ",
|
|
}
|
|
)
|
|
|
|
func i2b(i int) (b []byte) {
|
|
b = make([]byte, 4)
|
|
binary.BigEndian.PutUint32(b, uint32(i))
|
|
return
|
|
}
|
|
|
|
type MP struct {
|
|
sync.Mutex
|
|
key []byte
|
|
}
|
|
|
|
func NewMP(p, name []byte) (*MP, error) {
|
|
salt := []byte(variant)
|
|
salt = append(salt, i2b(len(name))...)
|
|
salt = append(salt, name...)
|
|
key, err := scrypt.Key(p, salt, 32768, 8, 2, 64)
|
|
defer func() {
|
|
for i := range p {
|
|
p[i] = byte(0)
|
|
}
|
|
for i := range name {
|
|
name[i] = byte(0)
|
|
}
|
|
}()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &MP{key: key}, nil
|
|
}
|
|
|
|
func (mp *MP) PrintPassword(site string, counter int, tempType TemplateType) {
|
|
mp.Lock()
|
|
defer mp.Unlock()
|
|
salt := []byte(variant)
|
|
salt = append(salt, i2b(len(site))...)
|
|
salt = append(salt, []byte(site)...)
|
|
salt = append(salt, i2b(counter)...)
|
|
mac := hmac.New(sha256.New, mp.key)
|
|
mac.Write(salt)
|
|
seed := mac.Sum(nil)
|
|
templates := typeMap[tempType]
|
|
temp := templates[int(seed[0])%len(templates)]
|
|
for i, c := range temp {
|
|
chars := charMap[c]
|
|
print(string(chars[int(seed[i+1])%len(chars)]))
|
|
}
|
|
print("\n")
|
|
}
|
|
|
|
func (mp *MP) DestroyKey() {
|
|
mp.Lock()
|
|
for i := range mp.key {
|
|
mp.key[i] = byte(0)
|
|
}
|
|
mp.key = nil
|
|
runtime.GC()
|
|
mp.Unlock()
|
|
}
|