anchor.diff:  -spec check_property_(InfoItem :: info_item()) -> Value :: any().
   check_property_({password, V}) when is_binary(V) ->
       V;
  +check_property_({password, {Algo, Salt, Encrypted} = V})
  +  when is_atom(Algo), is_binary(Salt), is_binary(Encrypted) ->
  +    V;
   check_property_({password, V}) when is_list(V) ->
       true = is_string(V),
  -    crypto:sha(V);
  +    Salt = crypto:rand_bytes(4),
  +    {sha, Salt, crypto:sha([Salt, V])};
   check_property_({created, V}) when ?is_now(V) ->
       V;
   check_property_({games, V}) ->
  
positive.code: -type info_item() ::
          {login, name()} |
          {password, ((ClearPassword :: nonempty_string()) |
                      (PasswordHash :: binary()))} |
          {created, erlang:timestamp()} |
          {fullname, string()} |
          {timezone, echessd_lib:administrative_offset()} |
  
negative.code:     end.
  
  %% @doc Authenticate the user. Return user properties on success.
  -spec auth(Name :: name(), ClearPassword :: nonempty_string()) ->
                    {ok, Info :: info()} | {error, Reason :: any()}.
  auth(Name, ClearPassword) ->
      case getprops(Name) of
          {ok, Info} = Ok ->
              case compare_password(
                     get_value(password, Info), ClearPassword) of
                  true ->
                      echessd_log:info(
                        "user ~9999p authenticated",
                        [Name]),
                      Ok;
                  false ->
                      Reason = password_incorrect,
                      echessd_log:err(
                        "user ~9999p authentication failed: ~9999p",
  