How to use 3DES encryption results to calculate the MAC value - c#

I have a project to do for work to do in C#. I have the requirements for a project and this part is just a small piece in the entire project. I was given test data and the result. I need to code it so that I get the correct results. And at the moment I'm not getting the final result.
Please don't question or criticise the requirements, it's what I have and need to sort out and code it.
I was told to take input string "abc" and compute the SHA-1 hash for this. I got this part to work, here is the code:
private string CalculateSHA1Hash(string text, Encoding characterEncoding)
{
byte[] buffer = characterEncoding.GetBytes(text);
SHA1CryptoServiceProvider sha1CryptoServiceProvider = new SHA1CryptoServiceProvider();
byte[] s = sha1CryptoServiceProvider.ComputeHash(buffer);
string hash = BitConverter.ToString(sha1CryptoServiceProvider.ComputeHash(buffer)).Replace("-", "");
return hash;
}
I used UTF8Encoding because none was specified in the requirements doc. The result that I got from this is A9993E364706816ABA3E25717850C26C9CD0D89D.
I was then told to break up this string into 3 string blocks, of 16 characters each, and use just the 1st block. This is what I got:
block1: A9993E364706816A
I was also given 2 keys:
K1: 0123456789ABCDEF
K2: FEDCBA9876543210
Block1 is to be used as input string to a 3DES encryption using the 2 keys.
The result of the cipher text must be 6E5271A3F3F5C418, I am not getting this.
Below is my calculations. Can someone please see if I am doing this correctly and where I am doing this wrong. Chris (on SO) gave me some articles to read but I still can't get the results that I need to get. Is there something that cater for this already, I'm I just totally confused, or what?
public string Encrypt(string message)
{
string result = string.Empty;
// Calculate the SHA1 hash
UTF8Encoding characterEncoding = new UTF8Encoding();
string sha1HashResult = CalculateSHA1Hash(message, characterEncoding);
block1 = sha1HashResult.Substring(0, 16);
byte[] block1ByteArray = characterEncoding.GetBytes(block1);
string key = "0x" + accessKey1 + accessKey2 + accessKey1;
byte[] keyByteArray = StringToByteArray(key).ToArray();
byte[] enc = ComputeTripleDesEncryption(block1ByteArray, keyByteArray);
result = ByteArrayToString(enc);
return result;
}
public byte[] ComputeTripleDesEncryption(byte[] plainText, byte[] key)
{
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = key;
des.GenerateIV();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.None;
ICryptoTransform ic = des.CreateEncryptor();
byte[] enc = ic.TransformFinalBlock(plainText, 0, plainText.Length);
return enc;
}
private byte[] StringToByteArray(String hex)
{
if (hex.Substring(0, 2) == "0x")
{
hex = hex.Substring(2);
}
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
private string ByteArrayToString(byte[] ba)
{
string hex = BitConverter.ToString(ba);
return hex.Replace("-", "");
}
I really do not know what to do further.

There's a few things wrong with what you have right now:
You're specifying that you need to use an IV, but you're using ECB (which doesn't use an IV)
You're generating the IV randomly, using GenerateIV(). This will cause the result to be different every time, if you're not using ECB.
You're only performing the transform on the final block, instead of the whole data.
See the following code sample for a decent idea of how to use 3DES in C#:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.tripledescryptoserviceprovider.aspx
I'd guess that since you're specifying an IV, you're actually meant to be using CBC instead of ECB. Try it out and see what you get.

Related

AES / RSA implementation from Python to C#

I want to migrate following python code into c#.
The entry point is the method encrypted_request
I have no real clue about aes/rsa in python or in c#.
Maybe someone could explain the different code sections and if possible give me a hint how to implement that in c#.
Especially the magic numbers used here and there I do not understand.
modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7'
'b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280'
'104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932'
'575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b'
'3ece0462db0a22b8e7')
nonce = '0CoJUm6Qyw8W8jud'
pubKey = '010001'
def encrypted_request(text):
text = json.dumps(text)
secKey = createSecretKey(16)
encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
encSecKey = rsaEncrypt(secKey, pubKey, modulus)
data = {'params': encText, 'encSecKey': encSecKey}
return data
def aesEncrypt(text, secKey):
pad = 16 - len(text) % 16
text = text + chr(pad) * pad
encryptor = AES.new(secKey, 2, '0102030405060708')
ciphertext = encryptor.encrypt(text)
ciphertext = base64.b64encode(ciphertext).decode('u8')
return ciphertext
def rsaEncrypt(text, pubKey, modulus):
text = text[::-1]
rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16)) % int(modulus, 16)
return format(rs, 'x').zfill(256)
def createSecretKey(size):
return binascii.hexlify(os.urandom(size))[:16]
Source: https://github.com/darknessomi/musicbox/blob/master/NEMbox/api.py
My current state in c#:
private byte[] hex2Binary(string hex) {
byte[] binaryVal = new byte[hex.Length];
for (int i = 0; i < hex.Length; i++) {
string byteString = hex.Substring(i, 1);
byte b = Convert.ToByte(byteString, 16);
binaryVal[i] = b;
}
return binaryVal;
}
private string aesEncryptBase64(String plainText, string key) {
return aesEncryptBase64(plainText, hex2Binary(key));
}
private string aesEncryptBase64(String plainText, byte[] key) {
//pad = 16 - len(text) % 16
//text = text + chr(pad) * pad
int pad = 16 - plainText.Length % 16;
for (int i=0; i<pad; i++) {
plainText = plainText + ((char)pad);
}
byte[] plainBytes = null;
RijndaelManaged aes = new RijndaelManaged();
//aes.KeySize = 16;
aes.Mode = CipherMode.CBC;
aes.Key = key;
aes.IV = hex2Binary(client.neteaseFix.encryptInfo.iv);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainBytes, 0, plainBytes.Length);
cs.Close();
byte[] encryptedBytes = ms.ToArray();
return Convert.ToBase64String(encryptedBytes); //decode("u8")
}
Here are a couple of things I see right off the bat, but the question is a bit too open-ended:
In aesEncryptBase64 you are manually applying padding. The AES implementation in .NET does that for you. If you prefer to do it yourself you need to set aes.Padding = PaddingMode.None
In aesEncryptBase64 you create a RijndaelManaged object. Don't do that. You want AES, just use AES.Create(), which returns an AES object (not a Rijndael object).
.NET had support for the larger Rijndael algorithm before AES; and Rijndael with a block size of 128 bits is what got selected as AES, but Rijndael supports modes that AES does not, and you shouldn't really use them interchangeably (though many samples do).
In aesEncryptBase64 your aes, ms, and cs objects are all IDisposable, so you should have them in using statements.
The rsaEncrypt method in Python is doing raw RSA, which isn't supported in .NET (nor generally considered a good idea). Unless it's only called by routines which do the padding (and then it's just a pit of side-channel vulnerabilities).
If your rsaEncrypt (in Python) is only being called from routines which do the signature or encryption (or PSS or OAEP) padding then your .NET equivalent would be (using your method naming casing, instead of the normal ones in .NET)
private static rsaEncrypt(string text, string pubKey, string modulus)
{
RSAParameters rsaParams = new RSAParameters
{
Exponent = hex2Binary(pubKey),
Modulus = hex2Binary(modulus),
};
using (RSA rsa = RSA.Create())
{
rsa.ImportParameters(rsaParams);
return rsa.Encrypt(Encoding.ASCII.GetBytes(text), YOUNEEDTOPICKTHEPADDINGMODE);
}
}
It would be worlds better to improve all of the code around this, though, so that it doesn't have to do so much string re-parsing.

Extract Salt From Password C# [duplicate]

This question already has answers here:
BitConverter.ToString() in reverse? [duplicate]
(7 answers)
Closed 8 years ago.
I have a function to calculate a SHA256 hash with a salt. The salt is then appended onto the hashed password and stored. The function for doing this looks like so:
public static string CalculateHash(string input)
{
var inputBuffer = new List<byte>(Encoding.Unicode.GetBytes(input));
var saltBytes = new byte[16];
using (var rnd = RandomNumberGenerator.Create())
{
rnd.GetBytes(saltBytes);
}
inputBuffer.AddRange(saltBytes);
byte[] hashedBytes;
using (var hasher = new SHA256Managed())
{
hashedBytes = hasher.ComputeHash(inputBuffer.ToArray());
}
var hash = BitConverter.ToString(hashedBytes).Replace("-", string.Empty);
var salt = BitConverter.ToString(saltBytes).Replace("-", string.Empty);
return string.Format("{0}:{1}", hash, salt);
}
It stores a string of 97 characters (including the ':') in length and seems to work well. I am struggling to strip the salt off of the hash when I retrieve it back. The issue I am having is converting the salt, in string form, back to a byte[16], which contains the original bytes. I assume once I have these original 16 bytes, I can append them to the user input, and hash the passwords to check for a match.
My current attempt is to split the hashed password and the salt at the colon delimiter and use a GetBytes function. It works like this:
public static bool ValidatePassword(string password, string hashWithSalt)
{
var split = hashWithSalt.Split(':');
var salt = split[1];
var saltBytes = GetBytes(salt);
}
private static byte[] GetBytes(string str)
{
var bytes = new byte[str.Length * sizeof(char)];
Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
But GetBytes is currently returning back byte[64], which is clearly not the original byte format. How can I go about fixing this?
Figured out my own solution. Just needed to change the GetBytes function to handle the hex conversion.
private static byte[] GetBytes(string str)
{
return Enumerable.Range(0, str.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(str.Substring(x, 2), 16))
.ToArray();
}

Simple string encryption/decryption with a small resulting string [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I need to encrypt a string and then be able to decrypt it again.
I implemented the solution here and it works well, but the resulting string is not suitable as it needs to be simple and short enough for a user to use.
I am encrypting incrementing database ID's (from 1) and there won't be more than 500. Ideally I'd like the encrypted string to be not more than 6 characters in length.
Any ideas appreciated..
edit: It's a lengthy form which the user can resume at a later date with this generated string
You can use AES in CTR mode without any padding. In this mode there is a counter that is encrypted and then the result is xor'd with your plaintext which is the number. The result should be small and you will get the encryption of AES which will be better than any substitution cipher you use (which you could probably break by hand). You will have to get the BouncyCastle crypto library however as the Microsoft implementation of Rijndael does not have CTR as an available mode. Below is an example of the AES class you would need to implement. As well as an example of encryption and decryption.
using System;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
public class AES
{
private readonly Encoding encoding;
private SicBlockCipher mode;
public AES(Encoding encoding)
{
this.encoding = encoding;
this.mode = new SicBlockCipher(new AesFastEngine());
}
public static string ByteArrayToString(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", string.Empty);
}
public static byte[] StringToByteArray(string hex)
{
int numberChars = hex.Length;
byte[] bytes = new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
public string Encrypt(string plain, byte[] key, byte[] iv)
{
byte[] input = this.encoding.GetBytes(plain);
byte[] bytes = this.BouncyCastleCrypto(true, input, key, iv);
string result = ByteArrayToString(bytes);
return result;
}
public string Decrypt(string cipher, byte[] key, byte[] iv)
{
byte[] bytes = this.BouncyCastleCrypto(false, StringToByteArray(cipher), key, iv);
string result = this.encoding.GetString(bytes);
return result;
}
private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, byte[] key, byte[] iv)
{
try
{
this.mode.Init(forEncrypt, new ParametersWithIV(new KeyParameter(key), iv));
BufferedBlockCipher cipher = new BufferedBlockCipher(this.mode);
return cipher.DoFinal(input);
}
catch (CryptoException)
{
throw;
}
}
}
Example Usage
string test = "1";
AES aes = new AES(System.Text.Encoding.UTF8);
RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
byte[] key = new byte[32];
byte[] iv = new byte[32];
// Generate random key and IV
rngCsp.GetBytes(key);
rngCsp.GetBytes(iv);
string cipher = aes.Encrypt(test, key, iv);
string plaintext = aes.Decrypt(cipher, key, iv);
Response.Write(cipher + "<BR/>");
Response.Write(plaintext);
Output Example
CB
1
//encryption
string output="";
char[] readChar = yourInput.ToCharArray();
for (int i = 0; i < readChar.Length; i++)
{
int no = Convert.ToInt32(readChar[i]) + 10;
string r = Convert.ToChar(no).ToString();
output+=r;
}
//decryption
string output="";
char[] readChar = yourInput.ToCharArray();
for (int i = 0; i < readChar.Length; i++)
{
int no = Convert.ToInt32(readChar[i]) - 10;
string r = Convert.ToChar(no).ToString();
output+=r;
}
if you want it to be simple maybe use a main key of 6 letter
add it to the 6 letters input do a modulo based on the allowed input chars
its like a =1
b =2
c = 3
and then simply add a number a + 13 mod 24 > ...
wont say its secure but its simple as you requested
You might also do some combinations like for the next char is deoded prev char as +xx
Since you said that these are database IDs that are incrementing I'm assuming we're talking about positive integers. Limiting encryption is really not a good idea because the more limited your encryption is the easier it becomes to break. I'm not sure of your goal but it sounds like you may want to simply hide the ID from the end user by "encrypting it". So, if my assumption about these being positive whole integers between 1 and 999 then my suggestions are as follows. One, a simple character substitution. It will be pretty easy to figure out since you'll be limited to 10 characters. Two, convert them to hexidecimal. Won't fool a lot of people but the average end user might not recognize it. Third, convert the number to Base64. This won't be recognized as easily as hexidecimal. Last, come up with some sort of formula you can apply to the number that will always yield a unique result. I really don't advise that however because it's pretty difficult.

How to decrypt an encrypted data in c# by using RSACryptoServiceProvider() in ubuntu?

I am encrypting my data by using RSACryptoServiceProvider() class in c#. I want to decrypt the data in ubuntu, that was encrypted in c#. Can you suggest me which mechanism I need to follow in order to decrypt. Following function is for encryption:
public static void Encrypt(String PublicKey, String plainText, out String cipherText)
{
try
{
int dwKeySize = 1024;
// TODO: Add Proper Exception Handlers
RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider(dwKeySize);
rsaCryptoServiceProvider.FromXmlString(PublicKey);
int keySize = dwKeySize / 8;
byte[] bytes = Encoding.UTF32.GetBytes(plainText);
// The hash function in use by the .NET RSACryptoServiceProvider here is SHA1
// int maxLength = ( keySize ) - 2 - ( 2 * SHA1.Create().ComputeHash( rawBytes ).Length );
int maxLength = keySize - 42;
int dataLength = bytes.Length;
int iterations = dataLength / maxLength;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i <= iterations; i++)
{
byte[] tempBytes = new byte[(dataLength - maxLength * i > maxLength) ? maxLength : dataLength - maxLength * i];
Buffer.BlockCopy(bytes, maxLength * i, tempBytes, 0, tempBytes.Length);
byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt(tempBytes, true);
// Be aware the RSACryptoServiceProvider reverses the order
// of encrypted bytes after encryption and before decryption.
// If you do not require compatibility with Microsoft Cryptographic API
// (CAPI) and/or other vendors.
// Comment out the next line and the corresponding one in the
// DecryptString function.
Array.Reverse(encryptedBytes);
// Why convert to base 64?
// Because it is the largest power-of-two base printable using only ASCII characters
stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
}
cipherText = stringBuilder.ToString();
}
catch (Exception e)
{
cipherText = "ERROR_STRING";
Console.WriteLine("Exception in RSA Encrypt: " + e.Message);
//throw new Exception("Exception occured while RSA Encryption" + e.Message);
}
}
Don't use RSA like that. It's not meant to be used that way and it's way too slow.
The right way is to use a symmetric algorithm, e.g. AES, and encrypt the key you used with RSA. See my old blog entry for C# code doing just that.
You need the same mechanisms, but in reverse. Try first, ask later.

C# Encrypt string with public RSA-1280 hex key

I've been trying to encrypt a password with a public RSA key that is sent to me by the server.
var csp = new CspParameters(1, "Microsoft Strong Cryptographic Provider");
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1280, csp);
byte[] key = ByteUtils.HexToBytes(client.RSAKey);
RSA.ImportCspBlob(key);
byte[] encrypted = RSA.Encrypt(Encoding.ASCII.GetBytes(password), true);
The hex key is provided in such format:
string key = "30819D300D06092A864886F70D010101050003818B0030818702818100C7BD672D8C634D443840AD809790852770D3A2E99F456D6516329E0205D0645C23FD001D4D070CEE368A20526FEB2402358C915D7E86102B1659AA8651C449C344599F72BE904B8E338E7002E9978453C5BBCCA51AC165AA265069E0EAB1411D11A2FFDD35E5A8296A6A2AF238945874E8206979B0A16E2E4260A161CAB5C905020111";
As the string is 320-bytes long in hex format, I assume the key is 160 bytes (RSA 1280)
Using this method, the provider keeps saying "Bad Version of provider.\r\n".
I've tried several methods, convert it to Base64, simply import it as ASCII / Unicode. Nothing worked so far.
EDIT: My HexToBytes function (which works afaik, it returns me correct 160-b array):
public static byte[] HexToBytes(string pValue)
{
// FIRST. Use StringBuilder.
StringBuilder builder = new StringBuilder();
// SECOND... USE STRINGBUILDER!... and LINQ.
foreach (char c in pValue.Where(IsHexDigit).Select(Char.ToUpper))
{
builder.Append(c);
}
// THIRD. If you have an odd number of characters, something is very wrong.
string hexString = builder.ToString();
if (hexString.Length % 2 == 1)
{
//throw new InvalidOperationException("There is an odd number of hexadecimal digits in this string.");
// I will just add a zero to the end, who cares (0 padding)
Log.WriteLine(LogLevel.Debug, "Hexstring had an odd number of hexadecimal digits.");
hexString += '0';
}
byte[] bytes = new byte[hexString.Length / 2];
// FOURTH. Use the for-loop like a pro :D
for (int i = 0, j = 0; i < bytes.Length; i++, j += 2)
{
string byteString = String.Concat(hexString[j], hexString[j + 1]);
bytes[i] = HexToByte(byteString);
}
return bytes;
}
Your public key is not in the correct format. It is not a CSP blob. It is a DER encoded SubjectPublicKeyInfo structure. You can find source code to parse it or you can write your own. Here is one example of such code.

Categories

Resources