I have an example in C# and have to write the same in PHP.
request = request.Replace(sign, string.Empty);
byte[] sha1Request;
using (var shaM = new SHA1Managed())
{
sha1Request = shaM.ComputeHash(Encoding.UTF8.GetBytes(request));
}
log.InfoFormat($"request={request}. sha1Request={Convert.ToBase64String(sha1Request)}. Sign={sign}", request, Convert.ToBase64String(sha1Request));
var pubKey = (RSACryptoServiceProvider)FrontInterface.GetCertificate(checkFrontCertificateCod.Value).PublicKey.Key;
var isValid = pubKey.VerifyData(Encoding.UTF8.GetBytes(Convert.ToBase64String(sha1Request)), new SHA1CryptoServiceProvider(), Convert.FromBase64String(sign));
if (!isValid)
{
throw new Exception("Wrong digital sign");
}
So, I may not convert string to bytes in php and line sha1Request = shaM.ComputeHash(Encoding.UTF8.GetBytes(request));
will be in PHP: sha1Request =sha1(request, true);
Am I rigth? If not, please help me to convert in PHP this line.
Thanks a lot.
Note that sha1 should not really be used any more for security relevant applications, it is out of date.
C# Version:
string text = "<Hällo World>";
byte[] sha1;
using (var shaM = new SHA1Managed())
{
sha1 = shaM.ComputeHash(Encoding.UTF8.GetBytes(text));
}
string encoded = Convert.ToBase64String(sha1);
Console.Write(encoded);
PHP Version:
$text = "<Hällo World>";
// Encode as UTF8 if necessary (May not be necessary if string is already utf-8)
$text = utf8_encode($text);
// Calculate SHA1
$sha1 = sha1($text, TRUE);
// Convert to Base64
$encoded = base64_encode($sha1);
echo($encoded);
Both versions should output
1nSiStZRa/quRru7Sqe+ejupqfs=
Note that the call to utf8_encode should only be there if the string you work with is not actually already encoded in utf8.
If the string is a literal in a *.php file, this depends on how the file is stored on the disk. (What character set it uses).
If the string is retrieved from a web request or from a database or from reading a file, this also depends on what character set the web form, the database or the external file use.
Related
(I've already been thru a lot of Stackoverflow/google results trying to find a fix for this.)
I am validating JWTs signed with RS256 using the default C# JwtSecurityTokenHandler. In some cases, the validation fails when it shouldn't. Concretely, tokens from a given Authorization Server validate properly while tokens form another Authorization Server won't.
BUT... Using the same JWTs and RSA Certificates on JWT.IO validates ALL the tokens succesfully. This is the part that makes me believe that there's something wrong/unusual in the C# implementation. I am also able to validate the same JWTs using the same Certificates using the oidc-client JavaScript library. The one place where the validation sometimes fails is in C#.
I traced the error down to JwtSecurityTokenHandler's ValidateSignature method. Searching the original github code and googling about RSA, I came down with this bare-bone method which allows me to reproduce the problem in a plain console app:
static void ValidateJWT(string token, string modulus, string exponent)
{
string tokenStr = token;
JwtSecurityToken st = new JwtSecurityToken(tokenStr);
string[] tokenParts = tokenStr.Split('.');
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(
new RSAParameters()
{
Modulus = FromBase64Url(modulus),
Exponent = FromBase64Url(exponent)
});
SHA256 sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(tokenParts[0] + '.' + tokenParts[1]));
RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
var valid = rsaDeformatter.VerifySignature(hash, FromBase64Url(tokenParts[2]));
Console.WriteLine(valid); // sometimes false when it should be true
}
private 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);
}
It is from that RSACryptoServiceProvider and using RSAKeys from here (https://gist.github.com/therightstuff/aa65356e95f8d0aae888e9f61aa29414) that I was able to Export the Public Key that allows me to validate JWTs successfully on JWT.IO.
string publicKey = RSAKeys.ExportPublicKey(rsa);
I can't provide actual JWTs to this post (they expire anyways), but does anyone knows of a crypto behavior specific to C# that could explain these validation errors, which don't happen in JavaScript nor on JWT.IO ?
And if so, any solution for this?
Thanks,
Martin
https://www.rfc-editor.org/rfc/rfc7518#section-6.3.1.1
Note that implementers have found that some cryptographic libraries
prefix an extra zero-valued octet to the modulus representations they
return, for instance, returning 257 octets for a 2048-bit key, rather
than 256. Implementations using such libraries will need to take
care to omit the extra octet from the base64url-encoded
representation.
In the case of one of the tokens you provided on a copy of this issue elsewhere, the decode of the modulus includes a prefixed 0x00 byte. This causes downstream problems. But you can fix their non-conformance.
byte[] modulusBytes = FromBase64Url(modulus);
if (modulusBytes[0] == 0)
{
byte[] tmp = new byte[modulusBytes.Length - 1];
Buffer.BlockCopy(modulusBytes, 1, tmp, 0, tmp.Length);
modulusBytes = tmp;
}
It looks like RS256 treats the signature as opaque bytes, so it will encode it as-is. So you probably don't need this correction (though it's where my investigation started):
byte[] sig = FromBase64Url(tokenParts[2]);
if (sig.Length < modulusBytes.Length)
{
byte[] tmp = new byte[modulusBytes.Length];
Buffer.BlockCopy(sig, 0, tmp, tmp.Length - sig.Length, sig.Length);
sig = tmp;
}
I'm about to download a page encoded in UTF-8.
So this is my code:
using (WebClient client = new WebClient())
{
client.Headers.Add("user-agent", Request.UserAgent);
htmlPage = client.DownloadString(HttpUtility.UrlDecode(resoruce_url));
var KeysParsed = HttpUtility.ParseQueryString(client.ResponseHeaders["Content-Type"].Replace(" ", "").Replace(";", "&"));
var charset = ((KeysParsed["charset"] != null) ? KeysParsed["charset"] : "UTF-8");
Response.Write(client.ResponseHeaders);
byte[] bytePage = Encoding.GetEncoding(charset).GetBytes(htmlPage);
using (var reader = new StreamReader(new MemoryStream(bytePage), Encoding.GetEncoding(charset)))
{
htmlPage = reader.ReadToEnd();
Response.Write(htmlPage);
}
}
so, it set UTF-8 for the encoding. But the downloaded title, for example, show in my screen as:
Sexy cover: 60 e più di “quei dischi” vietati ai minori
and not as:
Sexy cover: 60 e più di “quei dischi” vietati ai minori
somethings is wrong, but I don't find where. Any ideas?
The problem is that by the time you get the data it's already been converted.
When WebClient.DownloadString executes, it gets the raw bytes and converts them to a string using the default encoding. The damage is done. You can't take the resulting string, turn it back into bytes, and re-interpret it.
Put another way, this is what's happening:
// WebClient.DownloadString does, essentially, this.
byte[] rawBytes = DownloadData();
string htmlPage = Encoding.Default.GetString(rawBytes);
// Now you're doing this:
byte[] myBytes = Encoding.Utf8.GetBytes(htmlPage);
But myBytes will not necessarily be the same as rawBytes.
If you know what encoding to use beforehand, you can set the WebClient instance's Encoding property. If you want to interpret the string based on the encoding specified in the Content-Type header, then you have to download the raw bytes, determine the encoding, and use that to interpret the string. For example:
var rawBytes = client.DownloadData(HttpUtility.UrlDecode(resoruce_url));
var KeysParsed = HttpUtility.ParseQueryString(client.ResponseHeaders["Content-Type"].Replace(" ", "").Replace(";", "&"));
var charset = ((KeysParsed["charset"] != null) ? KeysParsed["charset"] : "UTF-8");
var theEncoding = Encoding.GetEncoding(charset);
htmlPage = theEncoding.GetString(rawBytes);
I need to encrypt text in python and decrypt in C #. In python, I have this code:
I have this code in Python:
def genKey():
rsa = RSA.gen_key(2048, 65537)
rsa.save_key('c:/temp/priv-key.pem', callback=passwordCallback)
rsa.save_pub_key('c:/temp/pub-key.pem')
def encrypt():
varkey = readkey('c:/temp/pub-key.pem')
bio = BIO.MemoryBuffer(varkey)
rsa = RSA.load_pub_key_bio(bio)
encrypted = rsa.public_encrypt('My Text Here.', RSA.pkcs1_oaep_padding)
f = open("c:/temp/cript.txt", "w")
f.write(encrypted)
f.close()
This code uses M2Crypto.
Like I said, I want to decrypt the result generated up in C #. Below is my code:
static void Main(string[] args)
{
string text = GetText();
System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();
Byte[] payload = encoding.GetBytes(text);
byte[] b = System.IO.File.ReadAllBytes(#"C:\temp\priv-key.pem");
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
OpenSSL.Core.BIO bio = new OpenSSL.Core.BIO(b);
OpenSSL.Crypto.CryptoKey key = OpenSSL.Crypto.CryptoKey.FromPrivateKey(bio, "mypassword");
RSA rsa = key.GetRSA();
byte[] result = rsa.PrivateDecrypt(payload, RSA.Padding.OAEP);
}
The problem is this line:
byte[] result = rsa.PrivateDecrypt(payload, RSA.Padding.OAEP);
When it is executed, this error occurs:
error:0407A079:rsa routines:RSA_padding_check_PKCS1_OAEP:oaep decoding error
error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
The gurus of Cryptography and C# can help me?
You are writing the encryption ciphertext as text. Instead you should open your file in binary mode in python. Then in C# you do the same thing, but the other way around. Here you should return bytes instead of a string as ciphertext.
If you want to use text mode instead of binary mode then you could use base 64 encoding/decoding.
I have generated and RSA public key :
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(4096);
var pub_key = rsaProvider.ExportParameters(false); // export public key
var priv_key = rsaProvider.ExportParameters(true); // export private key
I need a way to decode pub_key it into base64 so I can send it, any suggestions
When you say Base64 do you mean that you need the public key in Base64 PEM format? If so, consider using BouncyCastle.
var kp = [Org.BouncyCastle.Security.DotNetUtilities].GetKeyPair(rsaProvider);
using (var sw = new System.IO.StringWriter())
{
var pw = new Org.BouncyCastle.OpenSsl.PemWrite(sw);
pw.WriteObject(kp.Public);
var pem = sw.ToString();
return pem;
}
It is not clear exactly what you need but I'm guessing you are looking to serialize the key. In that case you can use the RSA.ToXmlString() method. If you really need to base64 encode it then you the method in Nickolay Olshevsky's answer to further encode the XML string.
In .NET there is a builtin function to convert to Base64 : http://msdn.microsoft.com/en-us/library/dhx0d524.aspx
I've got the following code sample in Java, and I need to re-enact it in C#:
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
Signature sign = Signature.getInstance("MD5withRSA");
sign.initSign(privKey);
sign.update(data);
byte[] signature = sign.sign();
Is it possible with the standard .Net Crypto API, or should I use BouncyCastle?
Thanks,
b.
Another way is to use CNG (Cryptography Next Generation), along with the Security.Cryptography DLL from CodePlex
Then you can write:
byte[] dataToSign = Encoding.UTF8.GetBytes("Data to sign");
using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsa = new RSACng(signingKey))
{
rsa.SignatureHashAlgorithm = CngAlgorithm.MD5;
return rsa.SignData(dataToSign);
}
Updated thanks to Simon Mourier: with .Net 4.6, you no longer need a separate library
I am running into a very similar problem trying to create a native C# tool for packing Chrome extensions (using SHA1, not MD5, but that's not a big difference). I believe I have tried literally every possible solution for .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net and Chilkat RSA.
The best solution is probably Chilkat; their interface is the cleanest and most straightforward, it's well-supported and well-documented, and there are a million examples. For instance, here's some code using their library that does something very close to what you want: http://www.example-code.com/csharp/rsa_signPkcs8.asp. However, it's not free (though $150 is not unreasonable, seeing as I have burned 2 days trying to figure this out, and I make a bit more than $75 a day!).
As a free alternative, JavaScience offers up a number of crypto utilities in source form for multiple languages (including C#/.Net) at http://www.jensign.com/JavaScience/cryptoutils/index.html. The one that's most salient to what you are trying to do is opensslkey (http://www.jensign.com/opensslkey/index.html), which will let you generate a RSACryptoServiceProvider from a .pem file. You can then use that provider to sign your code:
string pemContents = new StreamReader("pkcs8privatekey.pem").ReadToEnd();
var der = opensslkey.DecodePkcs8PrivateKey(pemContents);
RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(der);
signature = rsa.SignData(data, new MD5CryptoServiceProvider());
You can use this code . At the first you should download "BouncyCastle.Crypto.dll" from http://www.bouncycastle.org/csharp/ .
/// <summary>
/// MD5withRSA Signing
/// https://www.vrast.cn
/// keyle_xiao 2017.1.12
/// </summary>
public class MD5withRSASigning
{
public Encoding encoding = Encoding.UTF8;
public string SignerSymbol = "MD5withRSA";
public MD5withRSASigning() { }
public MD5withRSASigning(Encoding e, string s)
{
encoding = e;
SignerSymbol = s;
}
private AsymmetricKeyParameter CreateKEY(bool isPrivate, string key)
{
byte[] keyInfoByte = Convert.FromBase64String(key);
if (isPrivate)
return PrivateKeyFactory.CreateKey(keyInfoByte);
else
return PublicKeyFactory.CreateKey(keyInfoByte);
}
public string Sign(string content, string privatekey)
{
ISigner sig = SignerUtilities.GetSigner(SignerSymbol);
sig.Init(true, CreateKEY(true, privatekey));
var bytes = encoding.GetBytes(content);
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
return signedString;
}
public bool Verify(string content, string signData, string publickey)
{
ISigner signer = SignerUtilities.GetSigner(SignerSymbol);
signer.Init(false, CreateKEY(false, publickey));
var expectedSig = Convert.FromBase64String(signData);
/* Get the bytes to be signed from the string */
var msgBytes = encoding.GetBytes(content);
/* Calculate the signature and see if it matches */
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(expectedSig);
}
}
This SO question answers the PKCS#8 part of your code. The rest of the .NET RSA classes are a bizarre jumble of partially overlapping classes that are very difficult to fathom. It certainly appears that signature support is in either of the RSACryptoServiceProvider and/or RSAPKCS1SignatureFormatter classes.
Disclaimer: I know Java and cryptography, but my knowledge of C# and .NET is very limited. I am writing here only under the influence of my Google-fu skills.
Assuming that you could decode a PKCS#8-encoded RSA private key, then, from what I read on MSDN, the rest of the code should look like this:
byte[] hv = MD5.Create().ComputeHash(data);
RSACryptoServiceProvider rsp = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
// here fill rsp fields by decoding pkcs8PrivateKey
rsp.ImportParameters(key);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(rsp);
rf.SetHashAlgorithm("MD5");
byte[] signature = rf.CreateSignature(hv);
The relevant classes are in the System.Security.Cryptography namespace.
As for the PKCS#8 key blob decoding (i.e. filling in the rsp fields), I found this page which describes a command-line utility in C# which can perform that job. The source code is provided and is a single C# file. From what I read in it, that code decodes the PKCS#8 file "manually"; indirectly, this should mean that raw .NET (2.0) does not have facilities for PKCS#8 key file decoding (otherwise the author of that tool would not have went to the trouble of implementing such decoding). For your task at hand, you could scavenge from that source file the parts that you need, skipping anything about PEM and symmetric encryption; your entry point would be the DecodePrivateKeyInfo() function, which apparently expects a DER-encoded unencrypted PKCS#8 file, just like Java's PKCS8EncodedKeySpec.