improve (crypto): derivate secret_key for each usage to reduce attack surface in the worst case scenario

This commit is contained in:
Mickael KERJEAN
2019-01-18 13:48:04 +11:00
parent 7af12753ca
commit ec6eb0e8fa
10 changed files with 53 additions and 26 deletions

View File

@ -15,7 +15,6 @@ import (
var (
Config Configuration
configPath string = filepath.Join(GetCurrentDir(), CONFIG_PATH + "config.json")
SECRET_KEY string
)
type Configuration struct {
@ -321,7 +320,7 @@ func (this *Configuration) Initialise() {
}
this.Save()
}
SECRET_KEY = this.Get("general.secret_key").String()
InitSecretDerivate(this.Get("general.secret_key").String())
}
func (this Configuration) Save() Configuration {

View File

@ -16,4 +16,22 @@ const (
URL_SETUP = "/admin/setup"
)
var BUILD_NUMBER string
var (
BUILD_NUMBER string
SECRET_KEY string
SECRET_KEY_DERIVATE_FOR_PROOF string
SECRET_KEY_DERIVATE_FOR_ADMIN string
SECRET_KEY_DERIVATE_FOR_USER string
)
/*
* Improve security by calculating derivative of the secret key to restrict the attack surface
* in the worst case scenario with one compromise secret key
*/
func InitSecretDerivate(secret string) {
SECRET_KEY = secret
SECRET_KEY_DERIVATE_FOR_PROOF = Hash("PROOF_" + SECRET_KEY, len(SECRET_KEY))
SECRET_KEY_DERIVATE_FOR_ADMIN = Hash("ADMIN_" + SECRET_KEY, len(SECRET_KEY))
SECRET_KEY_DERIVATE_FOR_USER = Hash("USER_" + SECRET_KEY, len(SECRET_KEY))
}

View File

@ -6,8 +6,7 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha1"
"encoding/base32"
"crypto/sha256"
"encoding/base64"
"io"
"io/ioutil"
@ -45,10 +44,19 @@ func DecryptString(secret string, data string) (string, error){
return string(d), nil
}
func Hash(str string) string {
hasher := sha1.New()
func Hash(str string, n int) string {
hasher := sha256.New()
hasher.Write([]byte(str))
return "sha1::" + base32.HexEncoding.EncodeToString(hasher.Sum(nil))
d := hasher.Sum(nil)
size := len(Letters)
h := ""
for i:=0; i<len(d); i++ {
if n > 0 && i >= n {
break
}
h += string(Letters[int(d[i]) % size])
}
return h
}
func RandomString(n int) string {
@ -140,8 +148,8 @@ func verify(something []byte) ([]byte, error) {
// Create a unique ID that can be use to identify different session
func GenerateID(ctx *App) string {
p := ""
params := ctx.Session
p := "salt => " + SECRET_KEY
if params["type"] != "" {
p += "type =>" + params["type"]
}
@ -172,8 +180,10 @@ func GenerateID(ctx *App) string {
if params["token"] != "" {
p += "token =>" + params["token"]
}
if p == "salt => " + SECRET_KEY {
return ""
if p == "" {
return Hash("N/A", 20)
}
return Hash(p)
p += "salt => " + SECRET_KEY
return Hash(p, 20)
}

View File

@ -22,7 +22,7 @@ func AdminSessionGet(ctx App, res http.ResponseWriter, req *http.Request) {
return c.Value
}()
str, err := DecryptString(SECRET_KEY, obfuscate);
str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, obfuscate);
if err != nil {
SendSuccessResult(res, false)
return
@ -61,7 +61,7 @@ func AdminSessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Reques
// Step 3: Send response to the client
body, _ := json.Marshal(NewAdminToken())
obfuscate, err := EncryptString(SECRET_KEY, string(body))
obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, string(body))
if err != nil {
SendErrorResult(res, err)
return
@ -85,7 +85,7 @@ func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) {
}
if c, err := json.Marshal(backends); err == nil {
hash := Hash(string(c))
hash := Hash(string(c), 20)
if req.Header.Get("If-None-Match") == hash {
res.WriteHeader(http.StatusNotModified)
return

View File

@ -92,7 +92,7 @@ func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) {
cfg := Config.Export()
if c, err := json.Marshal(cfg); err == nil {
hash := Hash(string(c))
hash := Hash(string(c), 20)
if req.Header.Get("If-None-Match") == hash {
res.WriteHeader(http.StatusNotModified)
return

View File

@ -85,7 +85,7 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
Tmp1 interface{}
}{ files, perms }
if j, err := json.Marshal(tmp); err == nil {
return Hash(string(j))
return Hash(string(j), 20)
}
return ""
}()

View File

@ -72,7 +72,7 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
SendErrorResult(res, NewError(err.Error(), 500))
return
}
obfuscate, err := EncryptString(SECRET_KEY, string(s))
obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_USER, string(s))
if err != nil {
SendErrorResult(res, NewError(err.Error(), 500))
return

View File

@ -44,7 +44,7 @@ func ShareUpsert(ctx App, res http.ResponseWriter, req *http.Request) {
a, err := req.Cookie(COOKIE_NAME_AUTH)
if err != nil {
return ""
}
}
return a.Value
}
return ctx.Share.Auth
@ -146,7 +146,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
}
if submittedProof.Key != "" {
submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value)
submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value, 20)
verifiedProof = append(verifiedProof, submittedProof)
}
@ -158,7 +158,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
Name: COOKIE_NAME_PROOF,
Value: func(p []model.Proof) string {
j, _ := json.Marshal(p)
str, _ := EncryptString(SECRET_KEY, string(j))
str, _ := EncryptString(SECRET_KEY_DERIVATE_FOR_PROOF, string(j))
return str
}(verifiedProof),
Path: COOKIE_PATH,

View File

@ -30,7 +30,7 @@ func AdminOnly(fn func(App, http.ResponseWriter, *http.Request)) func(ctx App, r
return
}
str, err := DecryptString(SECRET_KEY, c.Value);
str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, c.Value);
if err != nil {
SendErrorResult(res, ErrPermissionDenied)
return
@ -195,7 +195,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
var session map[string]string = make(map[string]string)
if ctx.Share.Id != "" {
str, err = DecryptString(SECRET_KEY, ctx.Share.Auth)
str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, ctx.Share.Auth)
if err != nil {
// This typically happen when changing the secret key
return session, nil
@ -223,7 +223,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
return session, nil
}
str = cookie.Value
str, err = DecryptString(SECRET_KEY, str)
str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, str)
if err != nil {
// This typically happen when changing the secret key
return session, nil

View File

@ -261,7 +261,7 @@ func ShareProofGetAlreadyVerified(req *http.Request) []Proof {
if len(cookieValue) > 500 {
return p
}
j, err := DecryptString(SECRET_KEY, cookieValue)
j, err := DecryptString(SECRET_KEY_DERIVATE_FOR_PROOF, cookieValue)
if err != nil {
return p
}
@ -306,7 +306,7 @@ func shareProofAreEquivalent(ref Proof, p Proof) bool {
}
for _, chunk := range strings.Split(ref.Value, ",") {
chunk = strings.Trim(chunk, " ")
if p.Id == Hash(ref.Key + "::" + chunk) {
if p.Id == Hash(ref.Key + "::" + chunk, 20) {
return true
}
}