public function decode($challenge_message)
    {
        if (!is_string($challenge_message) || static::MINIMUM_MESSAGE_LENGTH >= strlen($challenge_message)) {
            throw new LengthException(
                sprintf(
                    'Provided challenge message isn\'t a %d-byte (or longer) string',
                    static::MINIMUM_MESSAGE_LENGTH
                )
            );
        }

        $invalidity_flags = null;

        $signature = substr($challenge_message, static::SIGNATURE_OFFSET, strlen(static::SIGNATURE));
        $message_type = unpack('V', substr($challenge_message, static::MESSAGE_TYPE_OFFSET, 4))[1];

        if (static::SIGNATURE !== $signature) {
            $invalidity_flags = $invalidity_flags | InvalidChallengeMessageException::CODE_FOR_INVALID_SIGNATURE;
        }

        if (static::MESSAGE_TYPE !== $message_type) {
            $invalidity_flags = $invalidity_flags | InvalidChallengeMessageException::CODE_FOR_INVALID_MESSAGE_TYPE;
        }

        if (null !== $invalidity_flags) {
            throw InvalidChallengeMessageException::forChallengeMessage($challenge_message, $invalidity_flags);
        }

        $target_name_length = unpack('v', substr($challenge_message, static::TARGET_NAME_LENGTH_OFFSET, 2))[1];
        $target_name_offset = unpack('V', substr($challenge_message, static::TARGET_NAME_BUFFER_OFFSET_OFFSET, 4))[1];

        $negotiate_flags_raw = substr(
            $challenge_message,
            static::NEGOTIATE_FLAGS_OFFSET,
            static::NEGOTIATE_FLAGS_LENGTH
        );
        $negotiate_flags = unpack('V', $negotiate_flags_raw)[1];

        $challenge_nonce = substr($challenge_message, static::CHALLENGE_NONCE_OFFSET, static::CHALLENGE_NONCE_LENGTH);

        $target_info_length = unpack('v', substr($challenge_message, static::TARGET_INFO_LENGTH_OFFSET, 2))[1];
        $target_info_offset = unpack('V', substr($challenge_message, static::TARGET_INFO_BUFFER_OFFSET_OFFSET, 4))[1];

        // Grab our payload data
        $target_name = null;
        $target_info = null;

        // Only actually decode the "TargetName" if we're told to
        if ((NegotiateFlag::REQUEST_TARGET & $negotiate_flags)
            === NegotiateFlag::REQUEST_TARGET) {
            $target_name = unpack('a*', substr($challenge_message, $target_name_offset, $target_name_length))[1];
        }

        // Only actually decode the target info if we're told to
        if ((NegotiateFlag::NEGOTIATE_TARGET_INFO & $negotiate_flags)
            === NegotiateFlag::NEGOTIATE_TARGET_INFO) {
            $target_info = unpack('a*', substr($challenge_message, $target_info_offset, $target_info_length))[1];
        }

        return new ServerChallenge(
            $challenge_nonce,
            $negotiate_flags,
            $target_name,
            $target_info
        );
    }
public function decode($challenge_message)
    {
        if (!is_string($challenge_message) || static::MINIMUM_MESSAGE_LENGTH >= strlen($challenge_message)) {
            throw new LengthException(
                sprintf(
                    'Provided challenge message isn\'t a %d-byte (or longer) string',
                    static::MINIMUM_MESSAGE_LENGTH
                )
            );
        }

        $invalidity_flags = null;

        $signature = substr($challenge_message, static::SIGNATURE_OFFSET, strlen(static::SIGNATURE));
        $message_type = unpack('V', substr($challenge_message, static::MESSAGE_TYPE_OFFSET, 4))[1];

        if (static::SIGNATURE !== $signature) {
            $invalidity_flags = $invalidity_flags | InvalidChallengeMessageException::CODE_FOR_INVALID_SIGNATURE;
        }

        if (static::MESSAGE_TYPE !== $message_type) {
            $invalidity_flags = $invalidity_flags | InvalidChallengeMessageException::CODE_FOR_INVALID_MESSAGE_TYPE;
        }

        if (null !== $invalidity_flags) {
            throw InvalidChallengeMessageException::forChallengeMessage($challenge_message, $invalidity_flags);
        }

        $target_name_length = unpack('v', substr($challenge_message, static::TARGET_NAME_LENGTH_OFFSET, 2))[1];
        $target_name_offset = unpack('V', substr($challenge_message, static::TARGET_NAME_BUFFER_OFFSET_OFFSET, 4))[1];

        $negotiate_flags_raw = substr(
            $challenge_message,
            static::NEGOTIATE_FLAGS_OFFSET,
            static::NEGOTIATE_FLAGS_LENGTH
        );
        $negotiate_flags = unpack('V', $negotiate_flags_raw)[1];

        $challenge_nonce = substr($challenge_message, static::CHALLENGE_NONCE_OFFSET, static::CHALLENGE_NONCE_LENGTH);

        $target_info_length = unpack('v', substr($challenge_message, static::TARGET_INFO_LENGTH_OFFSET, 2))[1];
        $target_info_offset = unpack('V', substr($challenge_message, static::TARGET_INFO_BUFFER_OFFSET_OFFSET, 4))[1];

        // Grab our payload data
        $target_name = null;
        $target_info = null;

        // Only actually decode the "TargetName" if we're told to
        if ((NegotiateFlag::REQUEST_TARGET & $negotiate_flags)
            === NegotiateFlag::REQUEST_TARGET) {
            $target_name = unpack('a*', substr($challenge_message, $target_name_offset, $target_name_length))[1];
        }

        // Only actually decode the target info if we're told to
        if ((NegotiateFlag::NEGOTIATE_TARGET_INFO & $negotiate_flags)
            === NegotiateFlag::NEGOTIATE_TARGET_INFO) {
            $target_info = unpack('a*', substr($challenge_message, $target_info_offset, $target_info_length))[1];
        }

        return new ServerChallenge(
            $challenge_nonce,
            $negotiate_flags,
            $target_name,
            $target_info
        );
    }
{@inheritDoc}