Store both masterKey and secretKey

This commit is contained in:
Neeraj Gupta 2023-09-22 17:48:14 +05:30
parent b4f0994a34
commit 652cf53e32
6 changed files with 46 additions and 32 deletions

View file

@ -54,12 +54,12 @@ func (c *ClICtrl) AddAccount(cxt context.Context) {
if authResponse.EncryptedToken == "" || authResponse.KeyAttributes == nil { if authResponse.EncryptedToken == "" || authResponse.KeyAttributes == nil {
panic("no encrypted token or keyAttributes") panic("no encrypted token or keyAttributes")
} }
masterKey, token, decErr := c.decryptMasterKeyAndToken(cxt, authResponse, keyEncKey) secretInfo, decErr := c.decryptMasterKeyAndToken(cxt, authResponse, keyEncKey)
if decErr != nil { if decErr != nil {
flowErr = decErr flowErr = decErr
return return
} }
err := c.storeAccount(cxt, email, authResponse.ID, app, masterKey, token) err := c.storeAccount(cxt, email, authResponse.ID, app, secretInfo)
if err != nil { if err != nil {
flowErr = err flowErr = err
return return
@ -68,7 +68,7 @@ func (c *ClICtrl) AddAccount(cxt context.Context) {
} }
} }
func (c *ClICtrl) storeAccount(_ context.Context, email string, userID int64, app api.App, masterKey, token []byte) error { func (c *ClICtrl) storeAccount(_ context.Context, email string, userID int64, app api.App, secretInfo *accSecretInfo) error {
// get password // get password
secret := GetOrCreateClISecret() secret := GetOrCreateClISecret()
err := c.DB.Update(func(tx *bolt.Tx) error { err := c.DB.Update(func(tx *bolt.Tx) error {
@ -79,8 +79,9 @@ func (c *ClICtrl) storeAccount(_ context.Context, email string, userID int64, ap
accInfo := model.Account{ accInfo := model.Account{
Email: email, Email: email,
UserID: userID, UserID: userID,
MasterKey: *model.MakeEncString(string(masterKey), secret), MasterKey: *model.MakeEncString(string(secretInfo.MasterKey), secret),
Token: *model.MakeEncString(string(token), secret), Token: *model.MakeEncString(string(secretInfo.Token), secret),
SecretKey: *model.MakeEncString(string(secretInfo.SecretKey), secret),
App: app, App: app,
} }
accInfoBytes, err := json.Marshal(accInfo) accInfoBytes, err := json.Marshal(accInfo)

View file

@ -10,6 +10,7 @@ type Account struct {
UserID int64 `json:"userID" binding:"required"` UserID int64 `json:"userID" binding:"required"`
App api.App `json:"app" binding:"required"` App api.App `json:"app" binding:"required"`
MasterKey EncString `json:"masterKey" binding:"required"` MasterKey EncString `json:"masterKey" binding:"required"`
SecretKey EncString `json:"secretKey" binding:"required"`
Token EncString `json:"token" binding:"required"` Token EncString `json:"token" binding:"required"`
} }

View file

@ -17,15 +17,15 @@ func MakeEncString(plainText string, key []byte) *EncString {
log.Fatalf("failed to encrypt %s", err) log.Fatalf("failed to encrypt %s", err)
} }
return &EncString{ return &EncString{
CipherText: utils.BytesToBase64(cipher), CipherText: utils.EncodeBase64(cipher),
Nonce: utils.BytesToBase64(nonce), Nonce: utils.EncodeBase64(nonce),
} }
} }
func (e *EncString) MustDecrypt(key []byte) string { func (e *EncString) MustDecrypt(key []byte) string {
plainBytes, err := crypto.DecryptChaCha20poly1305(utils.Base64DecodeString(e.CipherText), key, utils.Base64DecodeString(e.Nonce)) plainBytes, err := crypto.DecryptChaCha20poly1305(utils.DecodeBase64(e.CipherText), key, utils.DecodeBase64(e.Nonce))
if err != nil { if err != nil {
panic(err) panic(err)
} }
return utils.BytesToBase64(plainBytes) return utils.EncodeBase64(plainBytes)
} }

View file

@ -18,7 +18,7 @@ func (c *ClICtrl) SyncAccount(account model.Account) error {
return err return err
} }
token := account.Token.MustDecrypt(cliSecret) token := account.Token.MustDecrypt(cliSecret)
urlEncodedToken := base64.URLEncoding.EncodeToString(utils.Base64DecodeString(token)) urlEncodedToken := base64.URLEncoding.EncodeToString(utils.DecodeBase64(token))
c.Client.AddToken(account.AccountKey(), urlEncodedToken) c.Client.AddToken(account.AccountKey(), urlEncodedToken)
ctx := c.GetRequestContext(context.Background(), account) ctx := c.GetRequestContext(context.Background(), account)
return c.syncRemoteCollections(ctx, account) return c.syncRemoteCollections(ctx, account)

View file

@ -11,6 +11,12 @@ import (
"github.com/kong/go-srp" "github.com/kong/go-srp"
) )
type accSecretInfo struct {
MasterKey []byte
SecretKey []byte
Token []byte
}
func (c *ClICtrl) signInViaPassword(ctx context.Context, email string, srpAttr *api.SRPAttributes) (*api.AuthorizationResponse, []byte, error) { func (c *ClICtrl) signInViaPassword(ctx context.Context, email string, srpAttr *api.SRPAttributes) (*api.AuthorizationResponse, []byte, error) {
for { for {
// CLI prompt for password // CLI prompt for password
@ -28,18 +34,18 @@ func (c *ClICtrl) signInViaPassword(ctx context.Context, email string, srpAttr *
srpParams := srp.GetParams(4096) srpParams := srp.GetParams(4096)
identify := []byte(srpAttr.SRPUserID.String()) identify := []byte(srpAttr.SRPUserID.String())
salt := utils.Base64DecodeString(srpAttr.SRPSalt) salt := utils.DecodeBase64(srpAttr.SRPSalt)
clientSecret := srp.GenKey() clientSecret := srp.GenKey()
srpClient := srp.NewClient(srpParams, salt, identify, loginKey, clientSecret) srpClient := srp.NewClient(srpParams, salt, identify, loginKey, clientSecret)
clientA := srpClient.ComputeA() clientA := srpClient.ComputeA()
session, err := c.Client.CreateSRPSession(ctx, srpAttr.SRPUserID, utils.BytesToBase64(clientA)) session, err := c.Client.CreateSRPSession(ctx, srpAttr.SRPUserID, utils.EncodeBase64(clientA))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
serverB := session.SRPB serverB := session.SRPB
srpClient.SetB(utils.Base64DecodeString(serverB)) srpClient.SetB(utils.DecodeBase64(serverB))
clientM := srpClient.ComputeM1() clientM := srpClient.ComputeM1()
authResp, err := c.Client.VerifySRPSession(ctx, srpAttr.SRPUserID, session.SessionID, utils.BytesToBase64(clientM)) authResp, err := c.Client.VerifySRPSession(ctx, srpAttr.SRPUserID, session.SessionID, utils.EncodeBase64(clientM))
if err != nil { if err != nil {
log.Printf("failed to verify %v", err) log.Printf("failed to verify %v", err)
continue continue
@ -55,60 +61,66 @@ func (c *ClICtrl) decryptMasterKeyAndToken(
_ context.Context, _ context.Context,
authResp *api.AuthorizationResponse, authResp *api.AuthorizationResponse,
keyEncKey []byte, keyEncKey []byte,
) (masterKey, token []byte, err error) { ) (*accSecretInfo, error) {
var currentKeyEncKey []byte var currentKeyEncKey []byte
var masterKey, secretKey, tokenKey []byte
var err error
for { for {
if keyEncKey == nil { if keyEncKey == nil {
// CLI prompt for password // CLI prompt for password
password, flowErr := GetSensitiveField("Enter password") password, flowErr := GetSensitiveField("Enter password")
if flowErr != nil { if flowErr != nil {
return nil, nil, flowErr return nil, flowErr
} }
fmt.Println("\nPlease wait authenticating...") fmt.Println("\nPlease wait authenticating...")
currentKeyEncKey, err = enteCrypto.DeriveArgonKey(password, currentKeyEncKey, err = enteCrypto.DeriveArgonKey(password,
authResp.KeyAttributes.KEKSalt, authResp.KeyAttributes.MemLimit, authResp.KeyAttributes.OpsLimit) authResp.KeyAttributes.KEKSalt, authResp.KeyAttributes.MemLimit, authResp.KeyAttributes.OpsLimit)
if err != nil { if err != nil {
fmt.Printf("error deriving key encryption key: %v", err) fmt.Printf("error deriving key encryption key: %v", err)
return nil, nil, err return nil, err
} }
} else { } else {
currentKeyEncKey = keyEncKey currentKeyEncKey = keyEncKey
} }
encryptedKey := utils.Base64DecodeString(authResp.KeyAttributes.EncryptedKey) encryptedKey := utils.DecodeBase64(authResp.KeyAttributes.EncryptedKey)
encryptedKeyNonce := utils.Base64DecodeString(authResp.KeyAttributes.KeyDecryptionNonce) encryptedKeyNonce := utils.DecodeBase64(authResp.KeyAttributes.KeyDecryptionNonce)
key, keyErr := enteCrypto.SecretBoxOpen(encryptedKey, encryptedKeyNonce, currentKeyEncKey) key, keyErr := enteCrypto.SecretBoxOpen(encryptedKey, encryptedKeyNonce, currentKeyEncKey)
if keyErr != nil { if keyErr != nil {
if keyEncKey != nil { if keyEncKey != nil {
fmt.Printf("Failed to get key from keyEncryptionKey %s", keyErr) fmt.Printf("Failed to get key from keyEncryptionKey %s", keyErr)
return nil, nil, keyErr return nil, keyErr
} else { } else {
fmt.Printf("Incorrect password, error decrypting master key: %v", keyErr) fmt.Printf("Incorrect password, error decrypting master key: %v", keyErr)
continue continue
} }
} }
masterKey, keyErr = enteCrypto.SecretBoxOpen( secretKey, keyErr = enteCrypto.SecretBoxOpen(
utils.Base64DecodeString(authResp.KeyAttributes.EncryptedSecretKey), utils.DecodeBase64(authResp.KeyAttributes.EncryptedSecretKey),
utils.Base64DecodeString(authResp.KeyAttributes.SecretKeyDecryptionNonce), utils.DecodeBase64(authResp.KeyAttributes.SecretKeyDecryptionNonce),
key, key,
) )
if keyErr != nil { if keyErr != nil {
fmt.Printf("error decrypting master key: %v", keyErr) fmt.Printf("error decrypting master key: %v", keyErr)
return nil, nil, keyErr return nil, keyErr
} }
token, err = enteCrypto.SealedBoxOpen( tokenKey, err = enteCrypto.SealedBoxOpen(
utils.Base64DecodeString(authResp.EncryptedToken), utils.DecodeBase64(authResp.EncryptedToken),
utils.Base64DecodeString(authResp.KeyAttributes.PublicKey), utils.DecodeBase64(authResp.KeyAttributes.PublicKey),
masterKey, secretKey,
) )
if err != nil { if err != nil {
fmt.Printf("error decrypting token: %v", err) fmt.Printf("error decrypting token: %v", err)
return nil, nil, err return nil, err
} }
break break
} }
return masterKey, token, nil return &accSecretInfo{
MasterKey: masterKey,
SecretKey: secretKey,
Token: tokenKey,
}, nil
} }
func (c *ClICtrl) validateTOTP(ctx context.Context, authResp *api.AuthorizationResponse) (*api.AuthorizationResponse, error) { func (c *ClICtrl) validateTOTP(ctx context.Context, authResp *api.AuthorizationResponse) (*api.AuthorizationResponse, error) {

View file

@ -4,7 +4,7 @@ import (
"encoding/base64" "encoding/base64"
) )
func Base64DecodeString(s string) []byte { func DecodeBase64(s string) []byte {
b, err := base64.StdEncoding.DecodeString(s) b, err := base64.StdEncoding.DecodeString(s)
if err != nil { if err != nil {
panic(err) panic(err)
@ -12,6 +12,6 @@ func Base64DecodeString(s string) []byte {
return b return b
} }
func BytesToBase64(b []byte) string { func EncodeBase64(b []byte) string {
return base64.StdEncoding.EncodeToString(b) return base64.StdEncoding.EncodeToString(b)
} }