2018-04-25 06:17:20 +00:00
|
|
|
package scha
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha512"
|
2018-09-06 14:41:03 +00:00
|
|
|
"errors"
|
2018-07-24 13:31:38 +00:00
|
|
|
"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
|
|
|
}
|