I have written the following to decode JWT token, with the help of stackoverflow of course. I think there seems to be an issue with the public key.
Because it fails only at the key creation.
class Program
{
static void Main(string[] args)
{
string token = "TOKEN STRING";
string key = "KEY STRING";
string result = ValidateJWT(token, key);
Console.WriteLine(result);
}
public static string ValidateJWT(string tokenTodecode, string publicKey)
{
string[] parts = tokenTodecode.Split('.');
string header = parts[0];
string payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);
string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
JObject headerData = JObject.Parse(headerJson);
string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
JObject payloadData = JObject.Parse(payloadJson);
var keyBytes = Convert.FromBase64String(publicKey);
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
SHA256 sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));
RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
{
return "";
}
return payloadData.ToString();
}
public static byte[] Base64UrlDecode(string arg)
{
var decrypted = ToBase64(arg);
return Convert.FromBase64String(decrypted);
}
public static string ToBase64(string arg)
{
if (arg == null)
{
throw new ArgumentNullException("arg");
}
var s = arg
.PadRight(arg.Length + (4 - arg.Length % 4) % 4, '=')
.Replace("_", "/")
.Replace("-", "+");
return s;
}
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
return Convert.FromBase64String(base64);
}
}
And the following is the error I get. Can someone please help me to fix this ?
Is that the case that the key is wrong ?
Related
I need to encrypt my steam login password. Before sending the auth data, steam sends this: "publickey_mod":"c511d72db5ebbba01977983eec2...","publickey_exp":"010001".
The browser encrypts password with this script:
var pubKey = RSA.getPublicKey(results.publickey_mod, results.publickey_exp);
password = password.replace(/[^\x00-\x7F]/g, ''); // remove non-standard-ASCII characters
var encryptedPassword = RSA.encrypt(password, pubKey);
I can't write a working algorithm in c# which will encrypt the password using modulus and exponent.
Here is what i tried:
static async Task Main()
{
var pubKey = SetPublicKey($"{response["publickey_mod"]}", $"{response["publickey_exp"]}");
string password = "123456";
byte[] password_byte = Encoding.ASCII.GetBytes(password);
byte[] encryptedPassword;
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.ImportParameters(pubKey);
encryptedPassword = RSA.Encrypt(password_byte, false);
}
string encodingPassword = Convert.ToHexString(encryptedPassword);
Console.WriteLine(encodingPassword);
}
public static RSAParameters SetPublicKey(string modulus, string exponent)
{
RSAParameters result = new RSAParameters();
result.Modulus = Convert.FromHexString(modulus);
result.Exponent = Convert.FromHexString(exponent);
return result;
}
working algorithm:
byte[] encryptedPasswordBytes;
using (var rsaEncryptor = new RSACryptoServiceProvider())
{
var passwordBytes = Encoding.ASCII.GetBytes(password);
var rsaParameters = rsaEncryptor.ExportParameters(false);
rsaParameters.Exponent = Convert.FromHexString($"{_response_getrsakey["publickey_exp"]}");
rsaParameters.Modulus = Convert.FromHexString($"{_response_getrsakey["publickey_mod"]}");
rsaEncryptor.ImportParameters(rsaParameters);
encryptedPasswordBytes = rsaEncryptor.Encrypt(passwordBytes, false);
}
string encryptedPassword = Convert.ToBase64String(encryptedPasswordBytes);
here is my code.get error in encryption method
encryptedData = RSA.Encrypt(Data, DoOAEPPadding);
The method throws "Key not valid for use in specified state."
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
private void button1_Click(object sender, EventArgs e)
{
var rsa = new RSACryptoServiceProvider();
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var writer2 = new StringWriter();
var pemWriter = new PemWriter(writer);
var pemWriter2 = new PemWriter(writer2);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter2.WriteObject(rsaKeyPair.Private);
string Pub = writer.ToString();
string Prv = writer2.ToString();
plaintext = ByteConverter.GetBytes(txtplain.Text);
encryptedtext = Encryption(plaintext, Pub, false);
}
get error here when encrypt data using by RSA encryption method.here pass DATA as a byte and RSA public key as a string.after that convert it to RSAParanetrs "RSA.ImportParameters(GetRSAParameters(RSAKey));"
then encrypt data get this error.
static public byte[] Encryption(byte[] Data, string RSAKey, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.ImportParameters(GetRSAParameters(RSAKey));
encryptedData = RSA.Encrypt(Data, DoOAEPPadding); // get error "Key not valid for use in specified state"
}
return encryptedData;
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
private static RSAParameters GetRSAParameters(string pPublicKey)
{
byte[] lDer;
int lBeginStart = "-----BEGIN PUBLIC KEY-----".Length;
int lEndLenght = "-----END PUBLIC KEY-------".Length;
string KeyString = pPublicKey.Substring(lBeginStart, (pPublicKey.Length - lBeginStart - lEndLenght));
lDer = Convert.FromBase64String(KeyString);
RSAParameters lRSAKeyInfo = new RSAParameters();
lRSAKeyInfo.Modulus = GetModulus(lDer);
lRSAKeyInfo.Exponent = GetExponent(lDer);
return lRSAKeyInfo;
}
private static byte[] GetModulus(byte[] pDer)
{
string lModulus = BitConverter.ToString(pDer).Replace("-", "").Substring(58, 256);
return StringHexToByteArray(lModulus);
}
private static byte[] GetExponent(byte[] pDer)
{
int lExponentLenght = pDer[pDer.Length - 3];
string lExponent = BitConverter.ToString(pDer).Replace("-", "").Substring((pDer.Length * 2) - lExponentLenght * 2, lExponentLenght * 2);
return StringHexToByteArray(lExponent);
}
public static byte[] StringHexToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
I need to create a hash-signature in c#.
The pseudo-code example that i need to implement in my c# code:
Signatur(Request) = new String(encodeBase64URLCompatible(HMAC-SHA-256(getBytes(Z, "UTF-8"), decodeBase64URLCompatible(getBytes(S, "UTF-8")))), "UTF-8")
Z: apiSecret
S: stringToSign
The coding for expectedSignatur and apiSecret is Base64 URL Encoding [RFC 4648 Section 5]
My problem is that I always get the wrong result.
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
return Encoding.UTF8.GetString(base64EncodedBytes);
}
public static string Base64Encode(string plainText)
{
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(plainTextBytes);
}
private static byte[] HmacSha256(string data, string key)
{
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
{
return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
}
}
static void Main(string[] args)
{
var apiSecret = "JrXRHCnUegQJAYSJ5J6OvEuOUOpy2q2-MHPoH_IECRY=";
var stringToSign = "f3fea5f3-60af-496f-ac3e-dbb10924e87a:20160201094942:e81d298b-60dd-4f46-9ec9-1dbc72f5b5df:Qg5f0Q3ly1Cwh5M9zcw57jwHI_HPoKbjdHLurXGpPg0yazdC6OWPpwnYi22bnB6S";
var expectedSignatur = "ps9MooGiTeTXIkPkUWbHG4rlF3wuTJuZ9qcMe-Y41xE=";
apiSecret = apiSecret.Replace('-', '+').Replace('_', '/').PadRight(apiSecret.Length + (4 - apiSecret.Length % 4) % 4, '=');
var secretBase64Decoded = Base64Decode(apiSecret);
var hmac = Convert.ToBase64String(HmacSha256(secretBase64Decoded, stringToSign));
var signatur = hmac.Replace('+', '-').Replace('/', '_');
Console.WriteLine($"signatur: {signatur}");
Console.WriteLine($"expected: {expectedSignatur}");
Console.WriteLine(signatur.Equals(expectedSignatur));
Console.ReadLine();
}
You're assuming that your key was originally text encoded with UTF-8 - but it looks like it wasn't. You should keep logically binary data as binary data - you don't need your Base64Encode and Base64Decode methods at all. Instead, your HmacSha256 method should take a byte[] as a key, and you can just use Convert.FromBase64String to get at those bytes from the base64-encoded secret:
using System;
using System.Text;
using System.Security.Cryptography;
class Test
{
private static byte[] HmacSha256(byte[] key, string data)
{
using (var hmac = new HMACSHA256(key))
{
return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
}
}
static void Main(string[] args)
{
var apiSecret = "JrXRHCnUegQJAYSJ5J6OvEuOUOpy2q2-MHPoH_IECRY=";
var stringToSign = "f3fea5f3-60af-496f-ac3e-dbb10924e87a:20160201094942:e81d298b-60dd-4f46-9ec9-1dbc72f5b5df:Qg5f0Q3ly1Cwh5M9zcw57jwHI_HPoKbjdHLurXGpPg0yazdC6OWPpwnYi22bnB6S";
var expectedSignatur = "ps9MooGiTeTXIkPkUWbHG4rlF3wuTJuZ9qcMe-Y41xE=";
apiSecret = apiSecret.Replace('-', '+').Replace('_', '/').PadRight(apiSecret.Length + (4 - apiSecret.Length % 4) % 4, '=');
var secretBase64Decoded = Convert.FromBase64String(apiSecret);
var hmac = Convert.ToBase64String(HmacSha256(secretBase64Decoded, stringToSign));
var signatur = hmac.Replace('+', '-').Replace('/', '_');
Console.WriteLine($"signatur: {signatur}");
Console.WriteLine($"expected: {expectedSignatur}");
Console.WriteLine(signatur.Equals(expectedSignatur));
}
}
Personally I'd change your HmacSha256 method to:
private static byte[] ComputeHmacSha256Hash(byte[] key, byte[] data)
{
using (var hmac = new HMACSHA256(key))
{
return hmac.ComputeHash(data);
}
}
so that it's more general purpose, maybe adding another method to compute the hash after encoding as UTF-8 for convenience. That way you can sign any data, not just strings.
I use RSA cryptography to Enc/Dec message
Encryption is work well but when Decrypting I got This error on this line .
rsa.Decrypt(dataByte, false);
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Security.Cryptography.CryptographicException: The parameter is incorrect.
code is:
string en= x509_Encrypt(Current_Record_Hmac, PFXFile, s_pass);
string de= ByteToString( X509_Decrypt(en, PFXFile, s_pass));
public static byte[] X509_Decrypt(string data, string certificateFile, string password)
{
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
X509Certificate2 cert = new X509Certificate2(certificateFile, password);
var rsa = new RSACryptoServiceProvider();
var x509_privateKey = cert.PrivateKey;
string pri = x509_privateKey.ToString();
string x509_privateKey_ToString = x509_privateKey.ToString();
string X509_publicKey = ByteToString(cert.GetPublicKey());
x509_privateKey_ToString = rsa.ToXmlString(true);
X509_publicKey = rsa.ToXmlString(false);
rsa.FromXmlString(x509_privateKey_ToString);
var decryptedByte = rsa.Decrypt(dataByte, false);
return (decryptedByte);
}
public string x509_Encrypt(string input, string certificateFile, string password)
{
var dataToEncrypt = _encoder.GetBytes(input);
var encoding = new System.Text.ASCIIEncoding();
X509Certificate2 cert = new X509Certificate2(certificateFile, password);
var x509_privateKey = cert.PrivateKey;
string x509_privateKey_ToString = ByteToString(encoding.GetBytes(x509_privateKey.ToString()));
string X509_publicKey = ByteToString(cert.GetPublicKey());
//Encrypting the text using the public key
RSACryptoServiceProvider cipher = new RSACryptoServiceProvider();
x509_privateKey_ToString = cipher.ToXmlString(true);
X509_publicKey = cipher.ToXmlString(false);
cipher.FromXmlString(X509_publicKey);
var encryptedByteArray = cipher.Encrypt(dataToEncrypt, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
var sb = new StringBuilder();
foreach (var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length)
sb.Append(",");
}
return sb.ToString();
}
Try this for your decrypt method:
public string X509_Decrypt(string inputString, string pathToCertFile, string password)
{
if (inputString == null)
{
return null;
}
X509Certificate2 certificate = new X509Certificate2(pathToCertFile, password, X509KeyStorageFlags.MachineKeySet);
try
{
var cryptoProvider = (RSACryptoServiceProvider)certificate.PrivateKey;
int dwKeySize = cryptoProvider.KeySize;
int blockSize = ((dwKeySize / 8) % 3 != 0) ? (((dwKeySize / 8) / 3) * 4) + 4 : ((dwKeySize / 8) / 3) * 4;
int iterations = inputString.Length / blockSize;
var arrayList = new ArrayList();
for (int i = 0; i < iterations; i++)
{
byte[] encryptedBytes = Convert.FromBase64String(
inputString.Substring(blockSize * i, blockSize));
Array.Reverse(encryptedBytes);
arrayList.AddRange(cryptoProvider.Decrypt(encryptedBytes, true));
}
return Encoding.UTF32.GetString(arrayList.ToArray(Type.GetType("System.Byte")) as byte[]);
}
catch (Exception ex)
{
throw new SystemException(ex.Message);
}
}
And try this for your encrypt message:
public string X509_Encrypt(string inputString, string pathToCertFile, string password)
{
if (inputString == null)
{
return null;
}
X509Certificate2 certificate = new X509Certificate2(pathToCertFile, password, X509KeyStorageFlags.MachineKeySet);
try
{
// TODO: Add Proper Exception Handlers
var rsaCryptoServiceProvider = (RSACryptoServiceProvider)certificate.PublicKey.Key;
int keySize = rsaCryptoServiceProvider.KeySize / 8;
byte[] bytes = Encoding.UTF32.GetBytes(inputString);
int maxLength = keySize - 42;
int dataLength = bytes.Length;
int iterations = dataLength / maxLength;
var stringBuilder = new StringBuilder();
for (int i = 0; i <= iterations; i++)
{
var 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);
Array.Reverse(encryptedBytes);
stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
}
return stringBuilder.ToString();
}
catch (Exception ex)
{
throw new SystemException(ex.Message);
}
}
You cannot just convert bytes to characters like that. If you want to transmit the ciphertext as a string you need to use an encoding such as base 64 encoding and decode before decryption.
Looking for a way to do the following in C# from a string.
public static String sha512Hex(byte[] data)
Calculates the SHA-512 digest and returns the value as a hex string.
Parameters:
data - Data to digest
Returns:
SHA-512 digest as a hex string
private static string GetSHA512(string text)
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] hashValue;
byte[] message = UE.GetBytes(text);
SHA512Managed hashString = new SHA512Managed();
string encodedData = Convert.ToBase64String(message);
string hex = "";
hashValue = hashString.ComputeHash(UE.GetBytes(encodedData));
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
Would System.Security.Cryptography.SHA512 be what you need?
var alg = SHA512.Create();
alg.ComputeHash(Encoding.UTF8.GetBytes("test"));
BitConverter.ToString(alg.Hash).Dump();
Executed in LINQPad produces:
EE-26-B0-DD-4A-F7-E7-49-AA-1A-8E-E3-C1-0A-E9-92-3F-61-89-80-77-2E-47-3F-88-19-A5-D4-94-0E-0D-B2-7A-C1-85-F8-A0-E1-D5-F8-4F-88-BC-88-7F-D6-7B-14-37-32-C3-04-CC-5F-A9-AD-8E-6F-57-F5-00-28-A8-FF
To create the method from your question:
public static string sha512Hex(byte[] data)
{
using (var alg = SHA512.Create())
{
alg.ComputeHash(data);
return BitConverter.ToString(alg.Hash);
}
}
Got this to work. Taken from here and modified a bit.
public static string CreateSHAHash(string Phrase)
{
SHA512Managed HashTool = new SHA512Managed();
Byte[] PhraseAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(Phrase));
Byte[] EncryptedBytes = HashTool.ComputeHash(PhraseAsByte);
HashTool.Clear();
return Convert.ToBase64String(EncryptedBytes);
}
Better memory management:
public static string SHA512Hash(string value)
{
byte[] encryptedBytes;
using (var hashTool = new SHA512Managed())
{
encryptedBytes = hashTool.ComputeHash(System.Text.Encoding.UTF8.GetBytes(string.Concat(value)));
hashTool.Clear();
}
return Convert.ToBase64String(encryptedBytes);
}