Add Auth, add computeKeyPassword
This commit is contained in:
parent
24aec2c52a
commit
653a8a0dc0
|
@ -31,8 +31,10 @@ func main() {
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
code := scanner.Text()
|
code := scanner.Text()
|
||||||
|
|
||||||
err := c.Auth(username, password, code, nil)
|
auth, err := c.Auth(username, password, code, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println(auth)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,7 @@ const (
|
||||||
PasswordTwo = 2
|
PasswordTwo = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
type authResp struct {
|
type Auth struct {
|
||||||
resp
|
|
||||||
AccessToken string
|
AccessToken string
|
||||||
ExpiresIn int
|
ExpiresIn int
|
||||||
TokenType string
|
TokenType string
|
||||||
|
@ -88,17 +87,32 @@ type authResp struct {
|
||||||
UID string `json:"Uid"`
|
UID string `json:"Uid"`
|
||||||
RefreshToken string
|
RefreshToken string
|
||||||
EventID string
|
EventID string
|
||||||
ServerProof string
|
|
||||||
PasswordMode PasswordMode
|
PasswordMode PasswordMode
|
||||||
|
|
||||||
|
privateKey string
|
||||||
|
keySalt string
|
||||||
|
}
|
||||||
|
|
||||||
|
type authResp struct {
|
||||||
|
resp
|
||||||
|
Auth
|
||||||
|
ServerProof string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
KeySalt string
|
KeySalt string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo) error {
|
func (resp *authResp) auth() *Auth {
|
||||||
|
auth := &resp.Auth
|
||||||
|
auth.privateKey = resp.PrivateKey
|
||||||
|
auth.keySalt = resp.KeySalt
|
||||||
|
return auth
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo) (*Auth, error) {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
var err error
|
var err error
|
||||||
if info, err = c.AuthInfo(username); err != nil {
|
if info, err = c.AuthInfo(username); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +120,7 @@ func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo)
|
||||||
|
|
||||||
proofs, err := srp([]byte(password), info)
|
proofs, err := srp([]byte(password), info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reqData := &authReq{
|
reqData := &authReq{
|
||||||
|
@ -118,23 +132,22 @@ func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo)
|
||||||
ClientProof: base64.StdEncoding.EncodeToString(proofs.clientProof),
|
ClientProof: base64.StdEncoding.EncodeToString(proofs.clientProof),
|
||||||
TwoFactorCode: twoFactorCode,
|
TwoFactorCode: twoFactorCode,
|
||||||
}
|
}
|
||||||
log.Printf("%#v\n", reqData)
|
|
||||||
|
|
||||||
req, err := c.newJSONRequest(http.MethodPost, "/auth", reqData)
|
req, err := c.newJSONRequest(http.MethodPost, "/auth", reqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var respData authResp
|
var respData authResp
|
||||||
if err := c.doJSON(req, &respData); err != nil {
|
if err := c.doJSON(req, &respData); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%#v\n", respData)
|
log.Printf("%+v\n", respData)
|
||||||
|
|
||||||
if err := proofs.VerifyServerProof(respData.ServerProof); err != nil {
|
if err := proofs.VerifyServerProof(respData.ServerProof); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return respData.auth(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package protonmail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha512"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/emersion/go-bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const bcryptCost = 10
|
||||||
|
|
||||||
|
func hashBcrypt(password, salt []byte) ([]byte, error) {
|
||||||
|
hashed, err := bcrypt.GenerateFromPasswordAndSalt(password, bcryptCost, salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hashed = bytes.Replace(hashed, []byte("$2a$"), []byte("$2y$"), 1)
|
||||||
|
return hashed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandHash(b []byte) []byte {
|
||||||
|
var expanded []byte
|
||||||
|
var part [64]byte
|
||||||
|
|
||||||
|
part = sha512.Sum512(append(b, 0))
|
||||||
|
expanded = append(expanded, part[:]...)
|
||||||
|
|
||||||
|
part = sha512.Sum512(append(b, 1))
|
||||||
|
expanded = append(expanded, part[:]...)
|
||||||
|
|
||||||
|
part = sha512.Sum512(append(b, 2))
|
||||||
|
expanded = append(expanded, part[:]...)
|
||||||
|
|
||||||
|
part = sha512.Sum512(append(b, 3))
|
||||||
|
expanded = append(expanded, part[:]...)
|
||||||
|
|
||||||
|
return expanded
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashPassword(version int, password, salt, modulus []byte) ([]byte, error) {
|
||||||
|
switch version {
|
||||||
|
case 3, 4:
|
||||||
|
salt = append(salt, []byte("proton")...)
|
||||||
|
hashed, err := hashBcrypt(password, salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return expandHash(append([]byte(hashed), modulus...)), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unsupported auth version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeKeyPassword(password, salt []byte) ([]byte, error) {
|
||||||
|
hashed, err := hashBcrypt(password, salt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove bcrypt prefix and salt (first 29 characters)
|
||||||
|
return hashed[29:], nil
|
||||||
|
}
|
|
@ -63,7 +63,12 @@ func (c *Client) newJSONRequest(method, path string, body interface{}) (*http.Re
|
||||||
if err := json.NewEncoder(&b).Encode(body); err != nil {
|
if err := json.NewEncoder(&b).Encode(body); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.newRequest(method, path, &b)
|
req, err := c.newRequest(method, path, &b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) do(req *http.Request) (*http.Response, error) {
|
func (c *Client) do(req *http.Request) (*http.Response, error) {
|
||||||
|
@ -75,6 +80,8 @@ func (c *Client) do(req *http.Request) (*http.Response, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) doJSON(req *http.Request, respData interface{}) error {
|
func (c *Client) doJSON(req *http.Request, respData interface{}) error {
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
resp, err := c.do(req)
|
resp, err := c.do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,14 +3,12 @@ package protonmail
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha512"
|
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/emersion/go-bcrypt"
|
|
||||||
"golang.org/x/crypto/openpgp"
|
"golang.org/x/crypto/openpgp"
|
||||||
"golang.org/x/crypto/openpgp/clearsign"
|
"golang.org/x/crypto/openpgp/clearsign"
|
||||||
openpgperrors "golang.org/x/crypto/openpgp/errors"
|
openpgperrors "golang.org/x/crypto/openpgp/errors"
|
||||||
|
@ -33,41 +31,6 @@ func decodeModulus(msg string) ([]byte, error) {
|
||||||
return base64.StdEncoding.DecodeString(string(block.Plaintext))
|
return base64.StdEncoding.DecodeString(string(block.Plaintext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandHash(b []byte) []byte {
|
|
||||||
var expanded []byte
|
|
||||||
var part [64]byte
|
|
||||||
|
|
||||||
part = sha512.Sum512(append(b, 0))
|
|
||||||
expanded = append(expanded, part[:]...)
|
|
||||||
|
|
||||||
part = sha512.Sum512(append(b, 1))
|
|
||||||
expanded = append(expanded, part[:]...)
|
|
||||||
|
|
||||||
part = sha512.Sum512(append(b, 2))
|
|
||||||
expanded = append(expanded, part[:]...)
|
|
||||||
|
|
||||||
part = sha512.Sum512(append(b, 3))
|
|
||||||
expanded = append(expanded, part[:]...)
|
|
||||||
|
|
||||||
return expanded
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashPassword(version int, password, salt, modulus []byte) ([]byte, error) {
|
|
||||||
switch version {
|
|
||||||
case 3, 4:
|
|
||||||
salt = append(salt, []byte("proton")...)
|
|
||||||
hashed, err := bcrypt.GenerateFromPasswordAndSalt(password, 10, salt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hashed = bytes.Replace(hashed, []byte("$2a$"), []byte("$2y$"), 1)
|
|
||||||
return expandHash(append([]byte(hashed), modulus...)), nil
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unsupported auth version")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func reverse(b []byte) {
|
func reverse(b []byte) {
|
||||||
for i := 0; i < len(b)/2; i++ {
|
for i := 0; i < len(b)/2; i++ {
|
||||||
j := len(b) - 1 - i
|
j := len(b) - 1 - i
|
||||||
|
|
Loading…
Reference in New Issue