I am currently working on a program with Google's Directory API to reset the password of someone in my domain. I have it all working, but I would like to send an encrypted password to Google instead of plaintext. Since the API seems limited in what I can use to encrypt, I'm trying to use SHA-1 to do so. The problem is, when I encrypt it in SHA-1, Google doesn't accept it.
Here is my original code of what I was sending to Google:
//create a template of the user to update
var body = new Google.Apis.Admin.Directory.directory_v1.Data.User();
//Encrypt the password using SHA1
byte[] bytes = System.Text.Encoding.Unicode.GetBytes(model.NewPassword);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] password = sha.ComputeHash(bytes);
//Put the password and hash function into the request body
body.HashFunction = "SHA-1";
body.Password = password.ToString();
//send the request
var request = users.Update(body, email);
request.execute();
When I run this, it throws an error saying the password is invalid.
when I change it so that it is sending strictly hex, like so
//create a template of the user to update
var body = new Google.Apis.Admin.Directory.directory_v1.Data.User();
//Encrypt the password using SHA1
byte[] bytes = System.Text.Encoding.Unicode.GetBytes(model.NewPassword);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] password = sha.ComputeHash(bytes);
//Convert the hashcode to Hex
System.Text.StringBuilder builder = new System.Text.StringBuilder();
for (int i = 0; i < password.Length; i++)
{
builder.Append(password[i].ToString("x2"));
}
//Put the password and hash function into the request
body.HashFunction = "SHA-1";
body.Password = builder.ToString();
//send the request
var request = users.Update(body, email);
request.execute();
Then Google accepts what I've given it, but going into the account, I can't access it, because the password was changed to something completely different.
Am I just encrypting the password incorrectly, or is there something I'm missing?
(Disclaimer: I work for Google, but I haven't looked at this API before.)
Well, the problem when you call password.ToString()
is that it's not providing the hex representation - so that's why the first piece of code fails. It looks like it's basically expecting it to be hex. The documentation states:
We recommend sending the password property value as a base 16 bit encoded hash value. If a hashFunction is specified, the password must be a valid hash key.
Now, I suspect the problem with the second piece of code is the way you're converting the original text password to bytes. You're using:
Encoding.Unicode.GetBytes(model.NewPassword)
That's using little-endian UTF-16. While the documentation doesn't state the expected encoding, using UTF-8 would be more common. So I would suggest using
Encoding.UTF8.GetBytes(model.NewPassword)
instead... and then hashing the result and hex-encoding that hash as before.
That's only an educated guess, but it's worth a try.
See more on this question at Stackoverflow