public static Command Login(string user, string hash, uint[] passwordKey)
{
Command.SuccessCallBack successCallBack = (JToken result) =>
{
// these need to be moved to session class
uint[] u_storage_k;
string u_storage_sid;
object u_storage_privk;
LoginResonse login = result.ToObject<LoginResonse>();
var aes = new Sjcl.Cipher.Aes(passwordKey);
// decrypt master key
uint[] keyData = Crypto.base64_to_a32(login.k);
uint[] key = Crypto.decrypt_key(aes, keyData);
if (!string.IsNullOrEmpty(login.tsid))
{
// untested
byte[] t = Crypto.base64urldecode(login.tsid);
Debug.Assert(t.Length == 32);
byte[] t0 = t.Take(16).ToArray();
byte[] t1 = t.Skip(16).Take(16).ToArray();
byte[] bytes = Crypto.a32_to_str(Crypto.encrypt_key(aes, Crypto.str_to_a32(t0)));
if (Enumerable.SequenceEqual(bytes, t1))
{
u_storage_k = key;
u_storage_sid = login.tsid;
}
}
else if (!string.IsNullOrEmpty(login.csid))
{
uint[] t = Rsa.mpi2b(Crypto.base64urldecode(login.csid));
byte[] privk = Crypto.a32_to_str(Crypto.decrypt_key(aes, Crypto.base64_to_a32(login.privk)));
var rsa_privk = new uint[4][];
// decompose private key
int i;
for (i = 0; i < 4; ++i)
{
int l = ((privk[0] * 256 + privk[1] + 7) >> 3) + 2;
rsa_privk[i] = Rsa.mpi2b(privk.Take(l).ToArray());
if (false) { break; } // number??
privk = privk.Take(l).ToArray();
}
// check format
if ((i == 4) && (privk.Length < 16))
{
// @@@ check remaining padding for added early wrong password detection likelihood
u_storage_k = key;
byte[] s = Hex.b2s(Rsa.RSAdecrypt(t, rsa_privk[2], rsa_privk[0], rsa_privk[1], rsa_privk[3]));
u_storage_sid = Crypto.base64urlencode(s.Take(43).ToArray());
u_storage_privk = rsa_privk;
}
}
Console.WriteLine(login);
};
Command.ErrorCallBack errorCallBack = (Error result) =>
{
switch (result)
{
case Error.ENOENT:
Console.WriteLine("ENOENT");
break;
default:
Console.WriteLine(result);
break;
}
};
var command = new Command(_LoginSessionChallengeOrResponse, successCallBack, errorCallBack);
command.AddArgument("user", user);
command.AddArgument("uh", hash);
return command;
}