schastsp/internal/scha/hash.go

99 lines
2.3 KiB
Go

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