Use BLAKE2b checksum instead of SHA-1 and SHA-512

This commit is contained in:
nemunaire 2017-11-24 20:08:14 +01:00
parent 9325419002
commit e6e6e6c206
7 changed files with 58 additions and 38 deletions

View file

@ -2,7 +2,6 @@ package api
import ( import (
"bufio" "bufio"
"crypto/sha512"
"encoding/base32" "encoding/base32"
"encoding/hex" "encoding/hex"
"errors" "errors"
@ -14,6 +13,8 @@ import (
"strings" "strings"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/dchest/blake2b"
) )
var CloudDAVBase string var CloudDAVBase string
@ -29,13 +30,13 @@ type uploadedFile struct {
} }
func importFile(uf uploadedFile, next func(string, string, []byte) (interface{}, error)) (interface{}, error) { func importFile(uf uploadedFile, next func(string, string, []byte) (interface{}, error)) (interface{}, error) {
var hash [sha512.Size]byte var hash [blake2b.Size]byte
var logStr string var logStr string
var fromURI string var fromURI string
var getFile func(string) error var getFile func(string) error
if uf.URI != "" && len(uf.Parts) > 0 { if uf.URI != "" && len(uf.Parts) > 0 {
hash = sha512.Sum512([]byte(uf.URI)) hash = blake2b.Sum512([]byte(uf.URI))
logStr = fmt.Sprintf("Import file from Cloud: %s =>", uf.Parts) logStr = fmt.Sprintf("Import file from Cloud: %s =>", uf.Parts)
fromURI = uf.URI fromURI = uf.URI
getFile = func(dest string) error { getFile = func(dest string) error {
@ -53,12 +54,12 @@ func importFile(uf uploadedFile, next func(string, string, []byte) (interface{},
return nil return nil
} }
} else if uf.URI != "" { } else if uf.URI != "" {
hash = sha512.Sum512([]byte(uf.URI)) hash = blake2b.Sum512([]byte(uf.URI))
logStr = "Import file from Cloud: " + uf.URI + " =>" logStr = "Import file from Cloud: " + uf.URI + " =>"
fromURI = uf.URI fromURI = uf.URI
getFile = func(dest string) error { return getCloudFile(uf.URI, dest) } getFile = func(dest string) error { return getCloudFile(uf.URI, dest) }
} else if uf.Path != "" && len(uf.Parts) > 0 { } else if uf.Path != "" && len(uf.Parts) > 0 {
hash = sha512.Sum512([]byte(uf.Path)) hash = blake2b.Sum512([]byte(uf.Path))
logStr = fmt.Sprintf("Import file from local FS: %s =>", uf.Parts) logStr = fmt.Sprintf("Import file from local FS: %s =>", uf.Parts)
fromURI = uf.Path fromURI = uf.Path
getFile = func(dest string) error { getFile = func(dest string) error {
@ -81,7 +82,7 @@ func importFile(uf uploadedFile, next func(string, string, []byte) (interface{},
return nil return nil
} }
} else if uf.Path != "" { } else if uf.Path != "" {
hash = sha512.Sum512([]byte(uf.Path)) hash = blake2b.Sum512([]byte(uf.Path))
logStr = "Import file from local FS: " + uf.Path + " =>" logStr = "Import file from local FS: " + uf.Path + " =>"
fromURI = uf.Path fromURI = uf.Path
getFile = func(dest string) error { return os.Symlink(uf.Path, dest) } getFile = func(dest string) error { return os.Symlink(uf.Path, dest) }

View file

@ -74,6 +74,7 @@ func main() {
flag.StringVar(&api.CloudPassword, "cloudpass", "", "Password used to sync") flag.StringVar(&api.CloudPassword, "cloudpass", "", "Password used to sync")
flag.BoolVar(&api.RapidImport, "rapidimport", false, "Don't try to reimport an existing file") flag.BoolVar(&api.RapidImport, "rapidimport", false, "Don't try to reimport an existing file")
flag.BoolVar(&fic.OptionalDigest, "optionaldigest", false, "Is the digest required when importing files?") flag.BoolVar(&fic.OptionalDigest, "optionaldigest", false, "Is the digest required when importing files?")
flag.BoolVar(&fic.StrongDigest, "strongdigest", false, "Are BLAKE2b digests required instead of SHA-1 or BLAKE2b?")
flag.Parse() flag.Parse()
log.SetPrefix("[admin] ") log.SetPrefix("[admin] ")

View file

@ -70,7 +70,7 @@
<a ng-click="deleteFile()" class="btn btn-danger"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a> <a ng-click="deleteFile()" class="btn btn-danger"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
<button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button><br> <button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button><br>
Taille : <span title="{{ file.size }} octets">{{ file.size | size }}</span><br> Taille : <span title="{{ file.size }} octets">{{ file.size | size }}</span><br>
SHA-1 : <samp>{{ file.checksum | cksum }}</samp> BLAKE2b sum : <samp>{{ file.checksum | cksum }}</samp>
</form> </form>
</div> </div>
</div> </div>

View file

@ -21,7 +21,7 @@
<a ng-href="{{ file.path }}" target="_self" class="list-group-item" ng-repeat="file in my.exercices[current_exercice].files"> <a ng-href="{{ file.path }}" target="_self" class="list-group-item" ng-repeat="file in my.exercices[current_exercice].files">
<h1 class="pull-left" style="margin: 7px 7px 5px -5px"><span class="glyphicon glyphicon-download" aria-hidden="true"></span></h1> <h1 class="pull-left" style="margin: 7px 7px 5px -5px"><span class="glyphicon glyphicon-download" aria-hidden="true"></span></h1>
<h4 class="list-group-item-heading"><strong><samp>{{ file.name }}</samp></strong></h4> <h4 class="list-group-item-heading"><strong><samp>{{ file.name }}</samp></strong></h4>
<p class="list-group-item-text">Taille : <span title="{{ file.size }} octets">{{ file.size | size }}</span> &ndash; SHA-1 : <samp>{{ file.checksum }}</samp></p> <p class="list-group-item-text">Taille : <span title="{{ file.size }} octets">{{ file.size | size }}</span> &ndash; <a href="https://blake2.net/">b2sum</a> : <samp>{{ file.checksum }}</samp></p>
</a> </a>
</div> </div>
</div> </div>
@ -80,7 +80,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
Vérifiez les clefs que vous trouvez en comparant leur SHA-512 : Vérifiez les clefs que vous trouvez en comparant leur <a href="https://blake2.net/">BLAKE2b</a> :
</p> </p>
<dl class="dl-horizontal" ng-repeat="key in my.exercices[current_exercice].keys"> <dl class="dl-horizontal" ng-repeat="key in my.exercices[current_exercice].keys">
<dt title="{{ key.slice(128) }}">{{ key.slice(128) }}</dt> <dt title="{{ key.slice(128) }}">{{ key.slice(128) }}</dt>

View file

@ -110,7 +110,7 @@ CREATE TABLE IF NOT EXISTS exercice_files(
path VARCHAR(255) NOT NULL UNIQUE, path VARCHAR(255) NOT NULL UNIQUE,
id_exercice INTEGER NOT NULL, id_exercice INTEGER NOT NULL,
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
sha1 BINARY(20) NOT NULL, cksum BINARY(64) NOT NULL,
size INTEGER NOT NULL, size INTEGER NOT NULL,
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)
); );
@ -134,7 +134,7 @@ CREATE TABLE IF NOT EXISTS exercice_keys(
id_key INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_key INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_exercice INTEGER NOT NULL, id_exercice INTEGER NOT NULL,
type VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL,
value BINARY(64) NOT NULL, cksum BINARY(64) NOT NULL,
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)
); );
`); err != nil { `); err != nil {

View file

@ -9,10 +9,13 @@ import (
"os" "os"
"path" "path"
"strings" "strings"
"github.com/dchest/blake2b"
) )
var FilesDir string var FilesDir string
var OptionalDigest bool var OptionalDigest bool
var StrongDigest bool
type EFile struct { type EFile struct {
Id int64 `json:"id"` Id int64 `json:"id"`
@ -25,7 +28,7 @@ type EFile struct {
} }
func GetFiles() ([]EFile, error) { func GetFiles() ([]EFile, error) {
if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, sha1, size FROM exercice_files"); err != nil { if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, cksum, size FROM exercice_files"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -47,7 +50,7 @@ func GetFiles() ([]EFile, error) {
} }
func (e Exercice) GetFiles() ([]EFile, error) { func (e Exercice) GetFiles() ([]EFile, error) {
if rows, err := DBQuery("SELECT id_file, origin, path, name, sha1, size FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -80,28 +83,42 @@ func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (int
defer fd.Close() defer fd.Close()
reader := bufio.NewReader(fd) reader := bufio.NewReader(fd)
hash := sha1.New() hash160 := sha1.New()
if _, err := io.Copy(hash, reader); err != nil { hash512 := blake2b.New512()
w := io.MultiWriter(hash160, hash512)
if _, err := io.Copy(w, reader); err != nil {
return EFile{}, err return EFile{}, err
} }
result := hash.Sum(nil) result160 := hash160.Sum(nil)
result512 := hash512.Sum(nil)
if len(digest) != len(result) { if len(digest) != len(result512) {
return EFile{}, errors.New("Digests doesn't match: calculated: " + hex.EncodeToString(result) + " vs. given: " + hex.EncodeToString(digest)) if len(digest) != len(result160) {
} return EFile{}, errors.New("Digests doesn't match: calculated: sha1:" + hex.EncodeToString(result160) + " & blake2b:" + hex.EncodeToString(result512) + " vs. given: " + hex.EncodeToString(digest))
} else if StrongDigest {
return EFile{}, errors.New("Invalid digests: SHA-1 checksums are no more accepted. Calculated sha1:" + hex.EncodeToString(result160) + " & blake2b:" + hex.EncodeToString(result512) + " vs. given: " + hex.EncodeToString(digest))
}
for k := range result { for k := range result160 {
if result[k] != digest[k] { if result160[k] != digest[k] {
return EFile{}, errors.New("Digests doesn't match: calculated: " + hex.EncodeToString(result) + " vs. given: " + hex.EncodeToString(digest)) return EFile{}, errors.New("Digests doesn't match: calculated: sha1:" + hex.EncodeToString(result160) + " & blake2b:" + hex.EncodeToString(result512) + " vs. given: " + hex.EncodeToString(digest))
}
}
} else {
for k := range result512 {
if result512[k] != digest[k] {
return EFile{}, errors.New("Digests doesn't match: calculated: " + hex.EncodeToString(result512) + " vs. given: " + hex.EncodeToString(digest))
}
} }
} }
return e.AddFile(strings.TrimPrefix(filePath, FilesDir), origin, path.Base(filePath), result, fi.Size()) return e.AddFile(strings.TrimPrefix(filePath, FilesDir), origin, path.Base(filePath), result512, fi.Size())
} }
} }
func (e Exercice) AddFile(path string, origin string, name string, checksum []byte, size int64) (EFile, error) { func (e Exercice) AddFile(path string, origin string, name string, checksum []byte, size int64) (EFile, error) {
if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, sha1, size) VALUES (?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, size); err != nil { if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, cksum, size) VALUES (?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, size); err != nil {
return EFile{}, err return EFile{}, err
} else if fid, err := res.LastInsertId(); err != nil { } else if fid, err := res.LastInsertId(); err != nil {
return EFile{}, err return EFile{}, err
@ -111,7 +128,7 @@ func (e Exercice) AddFile(path string, origin string, name string, checksum []by
} }
func (f EFile) Update() (int64, error) { func (f EFile) Update() (int64, error) {
if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, sha1 = ?, size = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.Size, f.Id); err != nil { if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, cksum = ?, size = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.Size, f.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err
@ -130,6 +147,6 @@ func (f EFile) Delete() (int64, error) {
} }
} }
func (f EFile) GetOrigin() (string) { func (f EFile) GetOrigin() string {
return f.origin return f.origin
} }

View file

@ -1,19 +1,20 @@
package fic package fic
import ( import (
"crypto/sha512"
"time" "time"
"github.com/dchest/blake2b"
) )
type Key struct { type Key struct {
Id int64 `json:"id"` Id int64 `json:"id"`
IdExercice int64 `json:"idExercice"` IdExercice int64 `json:"idExercice"`
Type string `json:"type"` Type string `json:"type"`
Value []byte `json:"value"` Value [blake2b.KeySize]byte `json:"value"`
} }
func (e Exercice) GetKeys() ([]Key, error) { func (e Exercice) GetKeys() ([]Key, error) {
if rows, err := DBQuery("SELECT id_key, id_exercice, type, value FROM exercice_keys WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_key, id_exercice, type, cksum FROM exercice_keys WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -36,17 +37,17 @@ func (e Exercice) GetKeys() ([]Key, error) {
} }
} }
func getHashedKey(raw_value string) []byte { func getHashedKey(raw_value string) [blake2b.KeySize]byte {
hash := sha512.Sum512([]byte(raw_value)) hash := blake2b.Sum512([]byte(raw_value))
return hash[:] return hash
} }
func (e Exercice) AddRawKey(name string, raw_value string) (Key, error) { func (e Exercice) AddRawKey(name string, raw_value string) (Key, error) {
return e.AddKey(name, getHashedKey(raw_value)) return e.AddKey(name, getHashedKey(raw_value))
} }
func (e Exercice) AddKey(name string, value []byte) (Key, error) { func (e Exercice) AddKey(name string, value [blake2b.KeySize]byte) (Key, error) {
if res, err := DBExec("INSERT INTO exercice_keys (id_exercice, type, value) VALUES (?, ?, ?)", e.Id, name, value); err != nil { if res, err := DBExec("INSERT INTO exercice_keys (id_exercice, type, cksum) VALUES (?, ?, ?)", e.Id, name, value); err != nil {
return Key{}, err return Key{}, err
} else if kid, err := res.LastInsertId(); err != nil { } else if kid, err := res.LastInsertId(); err != nil {
return Key{}, err return Key{}, err
@ -56,7 +57,7 @@ func (e Exercice) AddKey(name string, value []byte) (Key, error) {
} }
func (k Key) Update() (int64, error) { func (k Key) Update() (int64, error) {
if res, err := DBExec("UPDATE exercice_keys SET id_exercice = ?, type = ?, value = ? WHERE id_key = ?", k.IdExercice, k.Type, k.Value, k.Id); err != nil { if res, err := DBExec("UPDATE exercice_keys SET id_exercice = ?, type = ?, cksum = ? WHERE id_key = ?", k.IdExercice, k.Type, k.Value, k.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
return 0, err return 0, err