schastsp/internal/scha/hash.go

99 lines
2.3 KiB
Go
Raw Normal View History

2018-04-25 06:17:20 +00:00
package scha
import (
"crypto/sha512"
2018-09-06 14:41:03 +00:00
"errors"
"git.xdrm.io/logauth/schastsp/internal/xor"
2018-04-25 06:17:20 +00:00
)
/* (0) Static
---------------------------------------------------------*/
/* (1) Constants */
2018-09-06 14:41:03 +00:00
const HSIZE uint16 = sha512.Size
const HBITSIZE uint32 = uint32(HSIZE) * 8
2018-04-25 06:17:20 +00:00
/* (1) Basic hash function
*
* @input<[]byte> Byte array input
*
* @return digest<[]byte]> Byte array digest
*
---------------------------------------------------------*/
2018-09-06 14:41:03 +00:00
func hash(input []byte) []byte {
2018-04-25 06:17:20 +00:00
/* (1) Create sha512 hasher */
2018-09-06 14:41:03 +00:00
hasher := sha512.New()
2018-04-25 06:17:20 +00:00
/* (2) Defer memory cleanup */
2018-09-06 14:41:03 +00:00
defer hasher.Reset()
2018-04-25 06:17:20 +00:00
/* (3) Set input to be hashed */
2018-09-06 14:41:03 +00:00
hasher.Write(input)
2018-04-25 06:17:20 +00:00
/* (4) Extract digest */
2018-09-06 14:41:03 +00:00
return hasher.Sum(nil)
2018-04-25 06:17:20 +00:00
}
/* (2) Public hashing interface
*
* @input<[]byte> Byte array input
* @depth<uint> Number of time to hash recursively (must be > 1)
* @salt<[]byte> [OPT] Optional salt
* @pepper<[]byte> [OPT] Optional pepper
*
* @return digest<[]byte]> Byte array digest
* @return err<error> If consistence error
*
---------------------------------------------------------*/
2018-09-06 14:41:03 +00:00
func Hash(input []byte, depth uint16, options ...[]byte) ([]byte, error) {
2018-04-25 06:17:20 +00:00
/* (1) Manage errors errors
---------------------------------------------------------*/
/* (1) Avoid no depth (no hash at all) */
2018-09-06 14:41:03 +00:00
if depth < 1 {
return nil, errors.New("Cannot use a 'depth' of zero. This is inconsistent and means that no hash will be processed")
2018-04-25 06:17:20 +00:00
}
/* (2) Avoir empty input */
2018-09-06 14:41:03 +00:00
if len(input) < 1 {
return nil, errors.New("Cannot use an empty 'input'. This is inconsistent")
2018-04-25 06:17:20 +00:00
}
/* (2) Extract optional arguments
---------------------------------------------------------*/
/* (1) Optional salt */
salt := make([]byte, 0)
2018-09-06 14:41:03 +00:00
if len(options) > 0 {
salt = options[0]
}
2018-04-25 06:17:20 +00:00
/* (2) Optional pepper */
pepper := make([]byte, 0)
2018-09-06 14:41:03 +00:00
if len(options) > 0 {
pepper = options[0]
}
2018-04-25 06:17:20 +00:00
/* (3) Process cyclic hash
---------------------------------------------------------*/
/* (1) Initialise digest */
digest := make([]byte, 0, HSIZE)
/* (2) Process first hash + salt */
2018-09-06 14:41:03 +00:00
digest = hash(xor.ByteArray(input, salt))
2018-04-25 06:17:20 +00:00
/* (3) Iterate @depth times */
for depth--; depth > 0; depth-- {
// Add Pepper only for last time
2018-09-06 14:41:03 +00:00
if depth == 1 {
digest = hash(xor.ByteArray(digest, pepper))
2018-04-25 06:17:20 +00:00
} else {
digest = hash(digest)
}
}
return digest, nil
2018-09-06 14:41:03 +00:00
}