// hash password and salt func (ctx *Context) hash(password []byte, salt []byte) ([]byte, error) { if len(password) == 0 { return nil, ErrPassword } if len(salt) == 0 { return nil, ErrSalt } hash := make([]byte, ctx.HashLen) // optional secret secret := (*C.uint8_t)(nil) if len(ctx.Secret) > 0 { secret = (*C.uint8_t)(&ctx.Secret[0]) } // optional associated data associatedData := (*C.uint8_t)(nil) if len(ctx.AssociatedData) > 0 { associatedData = (*C.uint8_t)(&ctx.AssociatedData[0]) } // optional flags flags := C.ARGON2_DEFAULT_FLAGS if ctx.Flags != 0 { flags = ctx.Flags } // wrapper to overcome go pointer passing limitations result := C.argon2_wrapper( (*C.uint8_t)(&hash[0]), C.uint32_t(ctx.HashLen), (*C.uint8_t)(&password[0]), C.uint32_t(len(password)), (*C.uint8_t)(&salt[0]), C.uint32_t(len(salt)), secret, C.uint32_t(len(ctx.Secret)), associatedData, C.uint32_t(len(ctx.AssociatedData)), C.uint32_t(ctx.Iterations), C.uint32_t(ctx.Memory), C.uint32_t(ctx.Parallelism), C.uint32_t(ctx.Parallelism), C.uint32_t(ctx.Version), nil, nil, C.uint32_t(flags), C.argon2_type(ctx.Mode)) if result != C.ARGON2_OK { return nil, Error(result) } return hash, nil }
// HashEncoded hashes a password and produces a crypt-like encoded string. func HashEncoded(ctx *Context, password []byte, salt []byte) (string, error) { if ctx == nil { return "", ErrContext } if len(password) == 0 { return "", ErrPassword } if len(salt) == 0 { return "", ErrSalt } encodedlen := C.argon2_encodedlen( C.uint32_t(ctx.Iterations), C.uint32_t(ctx.Memory), C.uint32_t(ctx.Parallelism), C.uint32_t(len(salt)), C.uint32_t(ctx.HashLen)) s := make([]byte, encodedlen) result := C.argon2_hash( C.uint32_t(ctx.Iterations), C.uint32_t(ctx.Memory), C.uint32_t(ctx.Parallelism), unsafe.Pointer(&password[0]), C.size_t(len(password)), unsafe.Pointer(&salt[0]), C.size_t(len(salt)), nil, C.size_t(ctx.HashLen), (*C.char)(unsafe.Pointer(&s[0])), C.size_t(encodedlen), C.argon2_type(ctx.Mode), C.uint32_t(ctx.Version)) if result != C.ARGON2_OK { return "", Error(result) } // Strip trailing null byte(s) s = bytes.TrimRight(s, "\x00") return string(s), nil }
// VerifyEncoded verifies an encoded Argon2 hash s against a plaintext password. func VerifyEncoded(s string, password []byte) (bool, error) { mode, err := getMode(s) if err != nil { return false, err } cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) result := C.argon2_verify( cs, unsafe.Pointer(&password[0]), C.size_t(len(password)), C.argon2_type(mode)) if result == C.ARGON2_OK { return true, nil } else if result == C.ARGON2_VERIFY_MISMATCH { return false, nil } // argon2_verify always seems to return an error in this case... return false, Error(result) }