194 lines
5.3 KiB
Go
194 lines
5.3 KiB
Go
package m
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"errors"
|
|
"go-nkode/util"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type UserCipherKeys struct {
|
|
AlphaKey []uint64
|
|
SetKey []uint64
|
|
PassKey []uint64
|
|
MaskKey []uint64
|
|
Salt []byte
|
|
MaxNKodeLen int
|
|
Kp *KeypadDimension
|
|
}
|
|
|
|
func NewUserCipherKeys(kp *KeypadDimension, setVals []uint64, maxNKodeLen int) (*UserCipherKeys, error) {
|
|
err := kp.IsValidKeypadDimension()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
setKey, err := util.GenerateRandomNonRepeatingUint64(kp.AttrsPerKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
setKey, err = util.XorLists(setKey, setVals)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
alphakey, _ := util.GenerateRandomNonRepeatingUint64(kp.TotalAttrs())
|
|
passKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
|
|
maskKey, _ := util.GenerateRandomNonRepeatingUint64(maxNKodeLen)
|
|
salt, _ := util.RandomBytes(10)
|
|
userCipherKeys := UserCipherKeys{
|
|
AlphaKey: alphakey,
|
|
PassKey: passKey,
|
|
MaskKey: maskKey,
|
|
SetKey: setKey,
|
|
Salt: salt,
|
|
MaxNKodeLen: maxNKodeLen,
|
|
Kp: kp,
|
|
}
|
|
return &userCipherKeys, nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) PadUserMask(userMask []uint64, setVals []uint64) ([]uint64, error) {
|
|
if len(userMask) > u.MaxNKodeLen {
|
|
return nil, errors.New("user mask length exceeds max nkode length")
|
|
}
|
|
paddedUserMask := make([]uint64, len(userMask))
|
|
copy(paddedUserMask, userMask)
|
|
for i := len(userMask); i < u.MaxNKodeLen; i++ {
|
|
paddedUserMask = append(paddedUserMask, setVals[i%len(setVals)])
|
|
}
|
|
return paddedUserMask, nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) ValidPassword(hashedPassword string, passcodeAttrIdx []int, attrVals []uint64) error {
|
|
hashBytes := []byte(hashedPassword)
|
|
passcodeCipher := u.encipherCode(passcodeAttrIdx, attrVals)
|
|
passwordDigest, err := u.saltAndDigest(passcodeCipher)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = bcrypt.CompareHashAndPassword(hashBytes, passwordDigest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) EncipherSaltHashCode(passcodeAttrIdx []int, attrVals []uint64) (string, error) {
|
|
passcodeCipher := u.encipherCode(passcodeAttrIdx, attrVals)
|
|
|
|
passcodeDigest, err := u.saltAndDigest(passcodeCipher)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
passcodeBytes, err := u.hashPasscode(passcodeDigest)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(passcodeBytes), nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) encipherCode(passcodeAttrIdx []int, attrVals []uint64) []uint64 {
|
|
passcodeLen := len(passcodeAttrIdx)
|
|
|
|
passcodeCipher := make([]uint64, u.MaxNKodeLen)
|
|
|
|
for idx := 0; idx < passcodeLen; idx++ {
|
|
attrIdx := passcodeAttrIdx[idx]
|
|
alpha := u.AlphaKey[attrIdx]
|
|
attrVal := attrVals[idx]
|
|
pass := u.PassKey[idx]
|
|
passcodeCipher[idx] = alpha ^ pass ^ attrVal
|
|
}
|
|
return passcodeCipher
|
|
}
|
|
|
|
func (u *UserCipherKeys) saltAndDigest(passcode []uint64) ([]byte, error) {
|
|
passcodeBytes := util.Uint64ArrToByteArr(passcode)
|
|
passcodeBytes = append(passcodeBytes, u.Salt...)
|
|
h := sha256.New()
|
|
passcodeSha, err := h.Write(passcodeBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
passcodeDigest := uint64(passcodeSha)
|
|
return util.Uint64ArrToByteArr([]uint64{passcodeDigest}), nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) hashPasscode(passcodeDigest []byte) ([]byte, error) {
|
|
|
|
hashedPassword, err := bcrypt.GenerateFromPassword(passcodeDigest, bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return hashedPassword, nil
|
|
}
|
|
func (u *UserCipherKeys) EncipherMask(passcodeSet []uint64, customerAttrs CustomerAttributes, userKp KeypadDimension) (string, error) {
|
|
setVals, err := customerAttrs.SetValsForKp(userKp)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
paddedPasscodeSets, err := u.PadUserMask(passcodeSet, setVals)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
cipheredMask := make([]uint64, len(paddedPasscodeSets))
|
|
for idx := range paddedPasscodeSets {
|
|
setIdx, err := customerAttrs.IndexOfSet(paddedPasscodeSets[idx])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
setKeyVal := u.SetKey[setIdx]
|
|
maskKeyVal := u.MaskKey[idx]
|
|
setVal := paddedPasscodeSets[idx]
|
|
cipheredMask[idx] = setKeyVal ^ maskKeyVal ^ setVal
|
|
}
|
|
mask := util.EncodeBase64Str(cipheredMask)
|
|
return mask, nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen int) ([]uint64, error) {
|
|
decodedMask, err := util.DecodeBase64Str(mask)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
decipheredMask, err := util.XorLists(decodedMask, u.MaskKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
setKeyRandComponent, err := util.XorLists(setVals, u.SetKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
passcodeSet := make([]uint64, passcodeLen)
|
|
for idx, setCipher := range decipheredMask[:passcodeLen] {
|
|
setIdx := util.IndexOf(setKeyRandComponent, setCipher)
|
|
passcodeSet[idx] = setVals[setIdx]
|
|
}
|
|
return passcodeSet, nil
|
|
}
|
|
|
|
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*EncipheredNKode, error) {
|
|
attrVals, err := customerAttrs.AttrValsForKp(*u.Kp)
|
|
code, err := u.EncipherSaltHashCode(passcodeAttrIdx, attrVals)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
passcodeSet := make([]uint64, len(passcodeAttrIdx))
|
|
|
|
for idx := range passcodeSet {
|
|
passcodeAttr := attrVals[passcodeAttrIdx[idx]]
|
|
passcodeSet[idx], err = customerAttrs.GetAttrSetVal(passcodeAttr, *u.Kp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
mask, err := u.EncipherMask(passcodeSet, customerAttrs, *u.Kp)
|
|
encipheredCode := EncipheredNKode{
|
|
Code: code,
|
|
Mask: mask,
|
|
}
|
|
return &encipheredCode, nil
|
|
}
|