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 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 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 }