AES128-ECB under UWP - c#

I need help in retrieving AES128-EBC encrypted string under Universal Windows Application.
I have a password in string that is used as a key. With it's 32 bits length MD5 hash value I would like to encrypt text with AES128-EBC.
Now I am using this for creating MD5Hash:
public string GetMD5Hash(String strMsg)
{
string strAlgName = HashAlgorithmNames.Md5;
IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm
string strAlgNameUsed = objAlgProv.AlgorithmName;
IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);
if (buffHash.Length != objAlgProv.HashLength)
{
throw new Exception("There was an error creating the hash");
}
string hex = CryptographicBuffer.EncodeToHexString(buffHash);
return hex;
}
And this code for encryption:
public string Encrypt(string input, string pass)
{
SymmetricKeyAlgorithmProvider provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
CryptographicKey key;
string encrypted = "";
byte[] keyhash = Encoding.ASCII.GetBytes(GetMD5Hash(pass));
key = provider.CreateSymmetricKey(CryptographicBuffer.CreateFromByteArray(keyhash));
IBuffer data = CryptographicBuffer.CreateFromByteArray(Encoding.Unicode.GetBytes(input));
encrypted = CryptographicBuffer.EncodeToBase64String(CryptographicEngine.Encrypt(key, data, null));
return encrypted;
}
The cause why I am using SymmetricAlgorithmNames.AesEcbPkcs7 is when I am using SymmetricAlgorithmNames.AesEcb the output string is empty. I don't understand why.
My question is: Does my code create an AES128-ECB encryption? Because I not really sure it does. Because the software that is waiting for that encrypted data not recognizes it, so it cannot decrypt it.

My question is: Does my code create an AES128-ECB encryption? Because I not really sure it does. Because the software that is waiting for that encrypted data not recognizes it, so it cannot decrypt it.
Yes, your code create an AES encryption with ECB cipher mode and PKCS7 padding. If I correctly understand your problem, you said this works with AesEcbPkcs7, but failed using AesEcb, your software for decryption doesn't work for this.
The difference between AesEcbPkcs7 and AesEcb is, AesEcbPkcs7 use PKCS#7 block padding modes, and PKCS #7 algorithms automatically pads the message to an appropriate length, so you don’t need to pad the cipher to a multiple of the block-size of the algorithm you are using. So if you insist to use AesEcb to encrypt, I recommend to use `AesEcbPkcs7, otherwise an exception: The supplied user buffer is not valid for the requested operation.
So I guess, one possibility here in your decryption software, it may have the ability to use AesEcbPkcs7, but it doesn't implement the decrytion of AesEcb. Here I tested decryption based on your code, this code can decrypt AesEcb correctly:
public string Decrypt(string input, string pass)
{
var keyHash = Encoding.ASCII.GetBytes(GetMD5Hash(pass));
// Create a buffer that contains the encoded message to be decrypted.
IBuffer toDecryptBuffer = CryptographicBuffer.DecodeFromBase64String(input);
// Open a symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider aes = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcb);
// Create a symmetric key.
var symetricKey = aes.CreateSymmetricKey(keyHash.AsBuffer());
var buffDecrypted = CryptographicEngine.Decrypt(symetricKey, toDecryptBuffer, null);
string strDecrypted = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, buffDecrypted);
return strDecrypted;
}
Another possibility I think you catch the exception when using AesEcb and the user buffer is not valid for the requested operation and handled it when you call your Encrypt(string input, string pass) method, the encryption failed actually.

Related

Why does RSA decryption fail in node.js when encrypted in C#?

I am creating a C# app that authenticates via a node.js server. I am using RSA for this purpose. I generated a public and private key for the server using crypto. Every time the client connects to the server, it generates a key pair for itself. The client gets the server public key from an endpoint. I have used XML strings as well as PEM strings, but neither of them worked. (using RSACryptoServiceProvider) When the server attempted to decrypt it, it threw an OAEP decoding error. I am trying to decrypt the message with the paired private key.
I have viewed other threads but they were not very helpful.
Here's the code for the server. It encrypts/decrypts with the built-in crypto module. (I have tested this with a node.js client and a node.js server, and it works.)
var encrypt = function(input, publicKey) {
var buffer = Buffer.from(input);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
var decrypt = function(input, privateKey) {
var buffer = Buffer.from(input, "base64");
var decrypted = crypto.privateDecrypt(privateKey, buffer);
return decrypted.toString("utf8");
};
module.exports = {
encrypt,
decrypt
}
Edit: I made a test C# console app that takes an input string and encrypts it with my node.js server's public key.
public const string pubKey = "<RSAKeyValue>public key etc etc</RSAKeyValue>";
private static void Main(string[] args)
{
string enc = encrypt(pubKey, args[0]);
Console.WriteLine(enc);
}
public static string encrypt(string publicKey, string decrypted)
{
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(publicKey);
byte[] bytesPlainTextData = Encoding.UTF8.GetBytes(decrypted);
byte[] bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
string cipherText = Convert.ToBase64String(bytesCipherText);
return cipherText;
}
It gave me the result VnzRc4yhIa9XcSDvHyDkwCNHFG6Ps2dddyCD4RHE4jIqvMl56DhmIJWprLRZle9EpZ/3Zq4fDkkplHUGBidoH+9VkPV/2+sV6P+C+4u6yisV5zTarZfjcvsShwBp/9z4YfOE7kQZVRENhvflrRw6GutxtDz0lO4KhvdvQztm0u7JmUB9ynM7XFYXOKT391InBs2eqRh+JRfJzTfhFqn3Bt8K/kKNE1xkvQV0GK7U1qSpWOWfB+0hdwNkUEQpT26jU93bAcex1SVwfbj4PJQMH6Wxzx2s6u4fcOzf9ELEgel/Fuj5b0UKHHE48B/zBmnoDsS3twt/8TJb9jbCU8S3ES/hKwndkS809bSoJl6TkBXErlOLCDpay3AO23+NjPGwSl1JvnFUVgTqAABd/yAcsokjIgxkbRqAvhC/js5Oh3y9wJwc9Z7V1ImPGcifIWsEBuH/8lerJdYw7ABB/eUZosC+tQkzvjr4H9urupM0mk6Zd+92sJaG/COrwOAPkiiM6lJK9ealRrlPMEKv39aWVr+brlQzN8zyoT+a0oGsYSPt9B/P3CJhbkbHqw9e1u9TZ7q9Ba7x/oqeRBmpRfFrcjegGFQkYViYkd1bswNF3KumqhBCsw4VeTkYmRNCKrLZdZyJ5BLSfvc+PTPOzDPVgOZb1InacmIWOqkapRbeELc=
Then, I did a simple console.log(decrypt(stringAbove, privateKey));
It still gives me the following error:
Error: error:04099079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
There are multiple types of padding, and apparently the encryption is trying to use PKCS1 (I guess), and the decryption defaults to OAEP.
In crypto.privateDecrypt you can set the padding to eg. padding: crypto.constants.RSA_PKCS1_PADDING and it should work.
You should go for OAEP on both ends if possible (and it should be), in which case your Node code is already ok as the default is OAEP, and C# should be set to OAEP too.
Edit: I mixed it up first, but the point is, you can set the padding type on either end, and they must match. :)

Encrypting Unity c# callout to node js server

I have a node server and and passing up usernames and passwords from unity. here is what I have so far. I am still trying to learn and understand encryption and there are so many types and Im just confused. The code below will successfully encrypt and decrypt the string. Is this code a good code to use for something like this or is there a better alternative? What type of encryption is this actually using? How would I decrypt this on node js? Any additional example, links, or comments would be much appreciated. Thanks!
public string encrypt(string toEncrypt) {
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "ThisIsAKey"; // This is the key used to encrypt and decrypt can be anything.
var provider = new RSACryptoServiceProvider(cspParams);
byte[] tempencryptedBytes = provider.Encrypt(System.Text.Encoding.UTF8.GetBytes(toEncrypt), true);
string encrypted = Convert.ToBase64String(tempencryptedBytes); // convert to base64string for storage
Debug.Log("encrypted: " + encrypted);
// Get the value stored in RegString and decrypt it using the key.
return encrypted;
}
public string decrypt(string toDecrypt) {
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "ThisIsAKey"; // This is the key used to encrypt and decrypt can be anything.
var provider = new RSACryptoServiceProvider(cspParams);
string decrypted = System.Text.Encoding.UTF7.GetString(provider.Decrypt(Convert.FromBase64String(toDecrypt), true));
Debug.Log("decrypted: " + decrypted);
return decrypted;
}
EDIT: SHA256 code that i used added here. It doesnt output the correct string value.
SHA256 sha256 = SHA256Managed.Create();
byte[] bytes = System.Text.Encoding.UTF8.GetBytes("randy");
byte[] hash = sha256.ComputeHash(bytes);
string result = "";
for (int i = 0; i < hash.Length; i++) {
result += String.Format("{0:x2}", i);
}
Debug.Log("hash: " + result);
string result2 = Convert.ToBase64String(hash);
Debug.Log("hash: " + result2);
If something is good to be used depends on the context.
If you need to pass a username / password combination then RSA encryption may indeed be used, preferably in addition to TLS transport security for the connection. If you just need to verify a username or password then you may need a password hash (or PBKDF) instead. The .NET version of PBKDF2 can be found in this badly named class.
Even if all the cryptographic algorithms are secure then your system may still not be secure. For instance, if you cannot trust the public key that you are encrypting with then you may be encrypting with a public key of an attacker.
So your code is using this specific encrypt call using a boolean to select the encryption algorithm. As the boolean is set to true that means that RSA with OAEP is being used, using the default SHA-1 hash function internally (which is secure for OAEP encryption, even if SHA-1 isn't). It's better to use the newer call where you can specify the padding without the boolean anti-pattern. In that case you can also specify the internal hash function to be used.
RSA with OAEP is specified in PKCS#1 v2.2, which is specified in turn in RFC 8017. This will even specify the byte order to be used (RSA operates on numbers in the end, which can be encoded to bytes in different ways). As long as you use a compliant library in any runtime and know how to encode / decode the plaintext and ciphertext (when using text) then you should be able to decrypt using any runtime that implements RSA with OAEP, if you have the matching private key of course.
As a general rule, passwords shouldn't be decryptable. You should hash the password (using something like SHA256), then compare that to a stored hash in your Node.js code. Never store or transfer passwords plaintext or in a method that can be converted back to the original password.
In C#, hashing will look something like:
string toHash = "PasswordToBehashed";
SHA256 sha = new SHA256();
byte[] tempencryptedBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(toHash));
For reference, see the SHA256 class and an example using MD5 instead of SHA256.

aes decryption not working properly sometime

I am using aes for encryption/decryption of the text but sometime its giving me exact value after decryption while some times i am getting error. I referred to different answers over but didn't get the root cause of my problem .
private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv)
{
// Declare the string used to hold the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new System.Security.Cryptography.RijndaelManaged())
{
//Settings
rijAlg.Mode = System.Security.Cryptography.CipherMode.CBC;
rijAlg.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
try
{
// Create the streams used for decryption.
using (var msDecrypt = new System.IO.MemoryStream(cipherText))
{
using (var csDecrypt = new System.Security.Cryptography.CryptoStream(msDecrypt, decryptor, System.Security.Cryptography.CryptoStreamMode.Read))
{
using (var srDecrypt = new System.IO.StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
catch
{
plaintext = "keyError";
}
}
return plaintext;
}
It throws error "Padding is invalid and cannot be removed"
I seen some suggestion like to remove padding but it didn't seems proper solution.
I am not able to find the cause behind this as sometimes it runs perfectly without throwing error .
Any help or suggestion is really appreciated.
For Encryption - The encryption is being done on to client side in js and passing encryped text to server.
var key = CryptoJS.enc.Utf8.parse("16 digit number here");
var iv = CryptoJS.enc.Utf8.parse("16 digit number here");
var EncryptedString = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse("entered string to encrypt"), key,
{ keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
By using a similar encryption routine in .NET to the decryption function you give I was able to successfully round-trip plaintext to ciphertext and back to plaintext, so it seems that the decryption function itself is ok. It therefore seems very likely that the key and/or IV you're using to encrypt does not match byte-for-byte with the values you're using when decrypting.
Given that your encryption code is using the UTF-8 encoded version of string values to form the key and IV, it would be worth doing the same in your decryption code (using Encoding.UTF8.GetBytes()).
However, it would be worth noting that whilst this might resolve the immediate issue, it is in itself a bad practice to use string values directly for keys without some form of key-derivation process (e.g. Rfc2898DeriveBytes), and IVs should be generated randomly for every application of the encryption function. Those are just a few issues with your use of cryptography (and are independent of whether the code works or not).

Encryption is not the same using the same method to encrypt the same plaintext

Use the same method below to encrypt the same plaintext twice,but the ciphertext are not the same after encryption.Why?
I want to encrypt my password when saving user information to database,and use the encryption method below.But I want to complete the edit-user feature,after inputing the old password and new password,find out the user according to the selected userid, and encrypt the old password,try to validate the old password typed is matched the password stored in database.But they never matched even though I input the right password.So is there any way to encrypt the password and validate if they are the same after using the same method to encrypt the password.
//encrypt the plainText
public static string Encrypt(string plainText)
{
if (plainText == null || plainText == "")
throw new ArgumentNullException("plainText");
var temp = Encoding.UTF8.GetBytes(plainText);
byte[] encrypted = ProtectedData.Protect(temp, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encrypted);
}
Based on the MSDN documentation of the ProtectedData class, it looks like it is performing 2-way encryption using a machine- or user-specific key. That means that if the machine or user that is active checking the key is different than the machine that originally encrypted it, you will get garbage results. If you only want to check the validity of a password, I would suggest a 1-way esecure hashing algorithm instead of 2-way encryption that supports decryption. Other posts on StackOverflow talk about using secure hashing algorithms (What is the most secure hashing algorithm in the .NET framework?).
Edit: I haven't tested this code on various systems under various users, but I expect it would work more universally because I don't expect that it is based on a machine or user key.
System.Security.Cryptography.SHA256Managed sha = new System.Security.Cryptography.SHA256Managed();
byte[] hashed = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(args[0]));
Console.WriteLine("Hash of {0}={1}", args[0], Convert.ToBase64String(hashed));
Edit 2: I would also add that my understanding of cryptography also suggests that you should probably include some "salt" in your hashed value. In other words, add something (like the user name) to the end of the password string before hashing it (both when entered and when checked) so that users with the same password don't end up with the same hash value, for example.
Some randomness in the output is actually a feature for encryption.
You get two choices:
If you ever need to recover the password from its encrypted form as part of your requirements, use encryption as you do, but decipher the result before making the comparison between expected and entered password.
If you don't really need to recover the password, use a hash algorithm instead (with a suitable salt). You'll be able to compare the two hashed values.
Here is something I threw together in a Console application. The Ciphers will not match, but as you can see, you can decrypt them just fine :)
class Program
{
private static string salt = "My Salt Brings All The Boys To The Yard... Wait A Second.....";
static void Main(string[] args)
{
for (int i = 0; 0 < 20; i++)
{
string password = "Guess my password!";
string cipher = Encrypt(password, salt);
string decipher = Decrypt(cipher, salt);
Console.WriteLine(decipher);
Thread.Sleep(500);
}
Console.ReadKey();
}
static public string Encrypt(string password, string salt)
{
byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
byte[] saltBytes = Encoding.Unicode.GetBytes(salt);
byte[] cipherBytes = ProtectedData.Protect(passwordBytes, saltBytes, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(cipherBytes);
}
static public string Decrypt(string cipher, string salt)
{
byte[] cipherBytes = Convert.FromBase64String(cipher);
byte[] saltBytes = Encoding.Unicode.GetBytes(salt);
byte[] passwordBytes = ProtectedData.Unprotect(cipherBytes, saltBytes, DataProtectionScope.CurrentUser);
return Encoding.Unicode.GetString(passwordBytes);
}
}

How to use c# to decrypt an MD5 hash that is encrypted using RSA1024

I trying to verify the integrity of a file at work and an having a hard time of it. I'm not very well versed with encryption and hashing, so bear with me.
I have some files that have an MD5 hash located at the end of them. I have written code to grab the bytes that I think are the hash and they seen to be uniformly 128 bytes long. In the file, just before the hash, is the keyword "RSA1024", which I have taken to mean the hash is encrypted using RSA 1024.
I have what I know is the RSA key in a file, and have read out the bytes (always 258 bytes long). I have seen many tutorials which use FromXmlString() to pull in the key, but this RSA key was not generated using the .net framework, and is not in an XML format.
I have written the following method to decrypt the hash data using the key, and it throws this error when executing ImportCspBlob() - System.Security.Cryptography.CryptographicException: Bad Version of provider.
Any ideas?
public byte[] DecryptRSA(byte[] encryptedData, byte[] keyData)
{
CspParameters param = new CspParameters();
param.Flags = CspProviderFlags.UseExistingKey;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
rsaProvider.ImportCspBlob(keyData);
byte[] decryptedData = rsaProvider.Decrypt(encryptedData, false);
return decryptedData;
}
Basic Algorithm
It may sound strange to want to "decrypt an MD5 hash", and especially when one says that they want to "decrypt it with a public key". But that is how digital signatures work. With RSA you can:
encrypt with private key
decrypt with the public key
The message digest is encrypted with the private key, and can then only be decrypted with the public key. That way you know that only the person with the private key could have signed the message.
Your key is most likely not a CSP-type key (it is most likely DER encoded). You can decrypt it using Bouncy Castle with the DER key like this:
RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(key);
byte[] rv = null;
RsaEngine eng = new RsaEngine();
eng.Init(false, privateKey);
int size = eng.GetOutputBlockSize();
rv = eng.ProcessBlock(cipher, 0, cipher.Length);
EDIT: to addressing GregS scenario that it may be a signature verify operation
If you are trying to verify a signature, you would need a certificate used to verify a message, the original message text, and the existing message signature to compare against.
What you do is pass in the original message text (minus the signature), the bytes of the message signature, and the path to the certificate you will use to verify the passed in signature.
Then, you will hash the original message and compare the result against the passed in signature.
Here is some code to illustrate:
private bool VerifySignature(string messageText, byte[] messageSignature, string certificatePath)
{
// Load the certificate from a file
X509Certificate2 cert = new X509Certificate2(certificatePath);
// Get public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
// Next, hash the messageText
SHA1Managed sha1 = new SHA1Managed();
byte[] messageBytes = Encoding.Unicode.GetBytes(messageText);
byte[] hash = sha1.ComputeHash(messageBytes);
// Verify the signature with the hash
return csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), messageSignature);
}
MD5 is one-way hash. But you might check out hashing algorithm. There are some ways to break this hash, just do some research ;)

Categories

Resources