I am trying to write client code that requests for information from an external API over the web.
The API is simple enough (to me) except for the stipulations of how to generate the authorisation key. First some context: There are 6 string values required to start with:
- token
- password
- devId
- salt
- orgId
- givenKey
Now for the encryption stuff. First up SHA2.
hashedString = SHA2(token + password + devId)
Followed by AES.
authKey = AES(salt + orgId + "=" + hashedString)
The AES parameters are specified as follows:
- Mode = ECB
- Padding = PKCS5Padding
- Secret Key = givenKey
My problem is that I know next to nothing about cryptography.
Below is the code I have attempting to accomplish the above.
// Generate Authorisation key
byte[] fieldsBytes = Encoding.ASCII.GetBytes(token + password + devId);
byte[] keyBytes = Encoding.ASCII.GetBytes(secretKey);
SHA512 shaM = new SHA512Managed();
string hashedFields = Encoding.ASCII.GetString(shaM.ComputeHash(fieldsBytes));
byte[] encryptedBytes = EncryptStringToBytes_Aes(salt + orgId + "=" + hashedfields,
keyBytes, keyBytes);
string encryptedString = Encoding.ASCII.GetString(encryptedBytes);
private byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.ECB;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
This code gets a "401" from the external service.
My first issue is that there does not seem to be a NET method named SHA2. The closest I could find is SHA512 and I am not sure if SHA512 is a .NET implementation of SHA2.
Secondly, padding for AES has been specified as PKCS5Padding but again the closest (naming-wise) I could find is PKCS7 which I am not sure about how similar it is to PKCS5.
There is also the matter of an Initialisation Vector (IV), which the AES parameters don't specify but I see C# AES examples including. In the code, I have set it to have the same value as the Key (which I believe is what the API calls "secret key") out of sheer desperation but I have tried making the request without setting IV to any value and still get back a 401.
I should probably also mention that I am using ASCII encoding to convert to-and-from bytes because I first tried using UTF8 but when it came to actually making the HTTP request, I was getting an exception saying that header values (remember we are generating an authorisation key that will be tucked in a HTTP request header) should only be encoded in ASCII.
Any help pointing me in the right direction will be immensely appreciated as I am woefully out of my depth with this cryptography stuff.