I want my application to encrypt a user password, and at one time password will be decrypted to be sent to the server for authentication. A friend advise me to use HMAC. I wrote the following code in C#:
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] key = encoding.GetBytes("secret");
HMACSHA256 myhmacsha256 = new HMACSHA256(key);
byte[] hashValue = myhmacsha256.ComputeHash(encoding.GetBytes("text"));
string resultSTR = Convert.ToBase64String(hashValue);
myhmacsha256.Clear();
How to decode the password (resultSTR, in this case)?
An HMAC (Hashed Message Authentication Code) is not encryption, it's hash function (in this case SHA-256) plus some secret key. It's lossy, there is no way to derive the plaintext from the HMAC.
If you want to encrypt some secret data, you should consider using the ProtectedData class instead. More infom including sample code at http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx
Related
I'm trying to validate a hmac sha256 key that an API sends to me in a header. I don't fully understand how to validate this, can anoyone point me in the right direction?
From the API reference:
Every central webhook POST contains a header field
"X-Signature-SHA256" with the signature value of the signed body's
payload. The JSON body is signed with the HMAC SHA256 algorithm based
on RFC2104, with the "Client Secret" as the signing key.
The following awnser is pretty clear & helpfull:
https://stackoverflow.com/a/12253723/4179234
However I feel like I'm missing a string/message that I need to encrypt to get the same hmac sha256 key, as I only have the api client secret to use as a key for the hasing but no message.
Following part is taken from the above stackoverlow awnser, so I convert the api client secret to byte[] and use it for the first input var. But what should message be then in this case?
private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
I want du encrypt and sign a mail with MimeKit.
Generating the Message works:
CmsRecipient CmsRecipient = new CmsRecipient("mail.cer");
CmsRecipient.EncryptionAlgorithms = new EncryptionAlgorithm[] { EncryptionAlgorithm.Aes192 };
to1.Add(CmsRecipient);
var signed = MultipartSigned.Create(ctx, signer, multipart);
var encrypted = ApplicationPkcs7Mime.Encrypt(ctx, to1, signed);
message.Body = MultipartSigned.Create(ctx, signer, encrypted);
In Outlook they arrive encrypted with: 168 Bit 3DES
But I need AES 265. How can I manage this?
I can set signing to RSA/SHA512 with
signer.DigestAlgorithm = DigestAlgorithm.Sha512;
but not the encryption.
Edit: Updated to my Solution
The CmsSigner specifies the DigestAlgorithm, but it's the CmsRecipient that specifies which encryption algorithm(s) that the recipient supports.
The way that the encryption algorithm is chosen by MimeKit is that it figures out the best encryption algorithm supported by each recipient and then uses that.
In other words, if you are encrypting to 5 recipients and all of them support AES256, then MimeKit will use AES256. But if one of the recipients only supports, for example, 3DES (and all of the other recipients also support 3DES as well as AES256), then 3DES is chosen instead.
I'm connecting to a web service within Visual Studio, I've got the parameters set up correctly, when triggered i get the error;
Length of the data to decrypt is invalid
This is due to Decryption, I have a AES key and IV not entirely sure how to apply this to the web service request.
AES Key: RijndaelManaged Key = new byte[] { 0x1, 0x2... 0x16 };
IV: RijndaelManaged IV = new byte[] { 0x1, 0x2... 0x16 }
I have checked a few threads about decryption, and from my findings they rely on creating the encryption to begin with. I have only been given the AES key and IV, ive been told its sufficient.
This is how I call the webservice;
AWebService.BIServiceClient Client = new AWebService.BIServiceClient();
Client.getTransactions(true, username, password, Period, Year, MethodSignature, Database);
Where would the decryption code go and how?
It sounds like the service is trying to decrpt the data (parameters) you are sending to it, but you have not encrypted them.
Use the key and iv to encrypt the appropriate parameters before calling:
Client.getTransactions(true, username, password, Period, Year, MethodSignature, Database);
as an aside, if you have been trying to call a production service with un-encrypted data you have to assume the password is possibly compromised. Consider changing it.
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.
So, I am creating a simple "web chat", using TcpClient and TcpListener class. I want all data sent to be encrpyted, and I am using AES encryption. So first I have to make sure AES key from server is securely sent to client. I am trying to achieve this, by encrypting AES key with RSA and then sending it to client and there decrypting it with RSA again.
So first of all I created an RSACryptoServiceProvider on server and extracted public key. I sent public key to client and there created RSACryptoServiceProvider and imported that key. When I call Decrpyt method I get an key does not exist exception. This is my code:
Server:
This is sending public key to client.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
string privateXml = rsa.ToXmlString(true);
string publicXml = rsa.ToXmlString(false);
Byte[] pubKey = Encoding.UTF8.GetBytes(publicXml);
clientStream.Write(pubKey, 0, pubKey.Length);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); // simetrično kriptiranje
byte[] aesKey = aes.Key;
byte[] encryptedRSA = rsa.Encrypt(aesKey, false);
clientStream.Write(encryptedRSA, 0, encryptedRSA.Length);
Client:
Byte[] serverPublicKey = new Byte[1024];
Int32 bytes1 = stream.Read(serverPublicKey, 0, serverPublicKey.Length);
string serverKey = Encoding.UTF8.GetString(serverPublicKey, 0, bytes1);
serverKey = serverKey.Replace("\0", "");
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(serverKey);
Byte[] bytes2 = new Byte[128];
String aesKey = null;
stream.Read(bytes2, 0, bytes2.Length);
byte[] decryptedKey = rsa.Decrypt(bytes2, false);
Sorry this wasn't small enough to fit in a comment.
You've sent the public key to the client. This will only allow the client to encrypt data to be sent to the server. To decrypt data the client would need a private key (hence your exception)
Sending your public key to someone does not allow you to send them encrypted messages, it allows them to send you encrypted messages securely, so in your example only the client can send an encrypted message.
In your scenario this would mean that the client would need to generate an AES key, encrypt it using the public key it has been been sent and then the server can decrypt it and use the AES key. HOWEVER I would not recommend this as it has many flaws including being very susceptible to a man in the middle attack. This is because we have no way to verify the public key we receive is the one that belongs to the server (some one else could be intercepting and modifying the tcp stream to be inserting their own key pair and thereby gaining access to the AES key and being able to snoop on the rest of the communication).
You should consider looking into using the SslStream class http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.100).aspx
If you wanted to carry on as you have been then you would need to let the client generate the key and have some mechanism to verify the public key received.
The usually way of verifying public keys is by using certificates (i.e. You have a third party (certificate authority) that both the server and client trusts and that third party has signed the public key to say it does actually belong to the server)
If you don't want to get a certificate that is signed by a trusted certificate authority then you could use a self signed certificate but there is not much benefit over just hardcoding the public key into the client application as you would have to hardcode the certificate thumbprint of the self signed certificate anyway.