I require a certain piece of encryption logic done in Java to be converted to C#
What would be the C# equivalent for the MessageDigest update , Digest and reset functions ?
In C#, the class is HashAlgorithm.
The equivalent to update is either TransformBlock(...) or TransformFinalBlock(...), after the final block version is called (you can also use an empty input) you can call the Hash property that will give you the digest value.
HashAlgorithm is likely to be reusable after final block is called (which means it is reset for the next time you call TransformBlock), you can double check if your HashAlgorithm supports reusing at all by checking the property CanReuseTransform.
The equivalent to your reset()/digest() combo is a one line byte[] ComputeHash(byte[]).
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(password.getBytes());
BigInteger hash = new BigInteger(1, md.digest());
hashword = hash.toString(16);
} catch (NoSuchAlgorithmException ex) {
/* error handling */
}
return hashword;
public static string HashPassword(string input)
{
var sha1 = SHA1Managed.Create();
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] outputBytes = sha1.ComputeHash(inputBytes);
return BitConverter.ToString(outputBytes).Replace("-", "").ToLower();
}
For a Digest in C#, similar to Java, you can use the class Windows.Security.Cryptography.Core. E.g., the following method returns a SHA256 hash, formatted in base64:
public static string sha256Hash(string data)
{
// create buffer and specify encoding format (here utf8)
IBuffer input = CryptographicBuffer.ConvertStringToBinary(data,
BinaryStringEncoding.Utf8);
// select algorithm
var hasher = HashAlgorithmProvider.OpenAlgorithm("SHA256");
IBuffer hashed = hasher.HashData(input);
// return hash in base64 format
return CryptographicBuffer.EncodeToBase64String(hashed);
}
See (mbrit): How to create SHA-256 hashes in WinRT?
Related
I'm having trouble finding a good example in encrypting / decrypting strings in C# using a certificate. I was able to find and implement an example of signing and validating a signature, as shown below. Could someone point me to an easy, similar example for encryption?
private static string Sign(RSACryptoServiceProvider privateKey, string content)
{
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding ();
byte[] data = encoding.GetBytes(content);
byte[] hash = sha1.ComputeHash(data);
// Sign the hash
var signature = privateKey.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
return Convert.ToBase64String(signature);
}
public static bool Verify(RSACryptoServiceProvider publicKey, string content, string hashString)
{
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding ();
byte[] data = encoding.GetBytes(content);
byte[] hash = sha1.ComputeHash(data);
return publicKey.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), Convert.FromBase64String(hashString));
}
Per the .NET Framework team's guidance (have to search for "Cryptography Updates", there doesn't seem to be an anchor nearby -- or, just look at the code samples).
public static byte[] EncryptDataOaepSha1(X509Certificate2 cert, byte[] data)
{
// GetRSAPublicKey returns an object with an independent lifetime, so it should be
// handled via a using statement.
using (RSA rsa = cert.GetRSAPublicKey())
{
// OAEP allows for multiple hashing algorithms, what was formermly just "OAEP" is
// now OAEP-SHA1.
return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA1);
}
}
Decrypt would thus be
public static byte[] DecryptDataOaepSha1(X509Certificate2 cert, byte[] data)
{
// GetRSAPrivateKey returns an object with an independent lifetime, so it should be
// handled via a using statement.
using (RSA rsa = cert.GetRSAPrivateKey())
{
return rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA1);
}
}
Caveats:
RSA.Encrypt(byte[], RSAEncryptionPadding) was added in .NET Framework 4.6 (and .NET Core 1.0 / .NET Standard 1.3), so make sure you are building a project with a high enough target version.
RSA encryption is mainly used to encrypt symmetric keys, not actual data payloads, because it is expensive and has a size limit (always lower than the keysize (in bytes), the different padding modes consume different amounts of available space).
While the RSA base class talks about OaepSHA256 (etc) only Pkcs1 and OaepSHA1 are supported by all providers in .NET Core. (OaepSHA256+ is limited to RSACng)
I am encrypting the message in .NET with RSACryptoServiceProvider with private key. (PKCS#1 v1.5)
When I try to decrypt in .NET with the following code that uses public key everything works fine:
private static string Decrypt(string key, string content)
{
byte[] rgb = Convert.FromBase64String(content);
var cryptoServiceProvider = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
cryptoServiceProvider.ImportCspBlob(Convert.FromBase64String(key));
return Convert.ToBase64String(cryptoServiceProvider.Decrypt(rgb, false));
}
When on the other hand I try to find an algorithm to make the same decrypt method in Android, I am failing to decrypt it properly with public key. I exported the modulus and exponent from public key in .NET in order to load it properly on Android.
The method in Android is here:
public String Decrypt(String input) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = "mmGn1IXB+/NEm1ecLiUzgz7g2L6L5EE5DUcptppTNwZSqxeYKn0AuAccupL0iyX3LMPw6Dl9pjPXDjk93TQwYwyGgZaXOSRDQd/W2Y93g8erpGBRm/Olt7QN2GYhxP8Vn+cWUbNuikdD4yMfYX9NeD9UNt5WJGFf+jRkLk0zRK0A7ZIS+q0NvGJ/CgaRuoe3x4Mh1qYP9ZWNRw8rsDbZ6N2zyUa3Hk/WJkptRa6jrzc937r3QYF3eDTurVJZHwC7c3TJ474/8up3YNREnpK1p7hqwQ78fn35Tw4ZyTNxCevVJfYtc7pKHHiwfk36OxtOIesfKlMnHMs4vMWJm79ctixqAe3i9aFbbRj710dKAfZZ0FnwSnTpsoKO5g7N8mKY8nVpZej7tcLdTL44JqWEqnQkocRqgO/p3R8V/6To/OjQGf0r6ut9y/LnlM5qalnKJ1gFg1D7gCzZJ150TX4AO5kGSAFRyjkwGxnR0WLKf+BDZ8T/syOrFOrzg6b05OxiECwCvLWk0AaQiJkdu2uHbsFUj3J2BcwDYm/kZiD0Ri886xHqZMNExZshlIqiecqCskQhaMVC1+aCm+IFf16Qg/+eMYCd+3jm/deezT4rcMBOV/M+muownGYQ9WOdjEK53h9oVheahD3LqCW8MizABFimvXR3wAgkIUvhocVhSN0=";
String exponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
PublicKey key = keyFactory.generatePublic(keySpec);
//at one point I read somewhere that .net reverses the byte array so that it needs to be reversed for java, but who knows any more
/*byte[] inputArrayReversed = Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT);
for (int i = 0; i < inputArrayReversed.length / 2; i++) {
byte temp = inputArrayReversed[i];
inputArrayReversed[i] = inputArrayReversed[inputArrayReversed.length - 1];
inputArrayReversed[inputArrayReversed.length - 1] = temp;
}*/
byte[] decryptedText = null;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedText = cipher.doFinal(Base64.decode(input.getBytes("UTF-8"), Base64.DEFAULT));
return Base64.encodeToString(decryptedText, Base64.NO_WRAP);
//return new String(decryptedText, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
Actually I tried also with different algorithms specified in Cypher class, also tried many other combinations, tried using SpongyCastle instead of built in Android RSA providers, but nothing worked. If anybody has any clue to point me in right direction, I would be absolutely grateful.
First hint is that decrypted string from .NET comes as around 25 characters long, and when I get Android to return decrypted string without exceptions it is usually much longer, around 500 bytes.
Second hint deleted
Third hint I also tried spongycastle, but it didn't help that much
Anyways, thank you in advance for any help!!!
UPDATE 1
Second hint is deleted because was wrong, disregard it. Now I have one question if the following can prove that the public key is loaded correctly, just to rule that problem out.
BigInteger modulus and exponent in the upper Android code and the following BigIntegers in .NET show equal integer values.
var parameters = csp.ExportParameters(false);
var modulusInteger = new BigInteger(parameters.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
var exponentInteger = new BigInteger(parameters.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
UPDATE 2
This and This SO answers provide some interesting clues
Heeh, the mistake was one of the basics, we had an architecture where we were doing encryption with public key and decryption with private key. The problem was in the architecture itself because as we initially set it up, we were sending private keys to all our client apps, which is big security flaw.
My mistake was that I assumed that on the client we have public key and actually from private key all the time I was trying to load the public key and then do decrypt.
If I knew the PKI in depth and communicated a bit better with my colleague, I could have noticed few things:
Decrypt can be done with private key only, while one the other hand verify can be done with public key, so when I saw Decrypt being used on client in .NET, I should have assumed that on the client we have private key (which is a security flaw in the end in the way we want to use PKI)
Few things that I already knew or learnt and want to share with others:
Private key should be kept secret, whether you want to have it on server or preferably only on one client because public key can easily be guessed from private key and then someone can easily repeat your whole encryption process easily and breach your security
PKI works for two scenarios:
First scenario is when you want to Encrypt something and that only specific person/computer can Decrypt it. In first scenario as you see, many stakeholders can have someone's Public key and send messages to him and that only he can read them with his Private key. Second scenario is when you want to be sure that the message that came to you was not altered and was sent by specific person/computer. In that case you Sign data with Private key and Verify it on the other end with Public key. The only process that is suitable for us is Sign <-> Verify because we send plain text license with signature in it, and thus on the client we want to be sure that nobody tampered with the plain text license and that it came from us.
In your code, if Decrypt or Verify functions throw exceptions in 50% of the time it is because of loading the incorrect key or incorrectly loading the correct key and in the other 50% it is because you are using the incorrect algorithm or because algorithm parameters are incorrectly set or because the algorithm implementations between platforms are incompatible (the last one is very rare)
.NET server code
public string Sign(string privateKey, string data)
{
_rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));
//// Write the message to a byte array using UTF8 as the encoding.
var encoder = new UTF8Encoding();
byte[] byteData = encoder.GetBytes(data);
//// Sign the data, using SHA512 as the hashing algorithm
byte[] encryptedBytes = _rsaProvider.SignData(byteData, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(encryptedBytes);
}
.NET client code (Win Mobile)
private bool Verify(string key, string signature, string data)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(key));
byte[] signatureBytes = Convert.FromBase64String(signature);
var encoder = new UTF8Encoding();
byte[] dataBytes = encoder.GetBytes(data);
return rsaProvider.VerifyData(dataBytes, new SHA1CryptoServiceProvider(), signatureBytes);
}
Android client code:
public boolean Verify(RSAPublicKey key, String signature, String data)
{
try
{
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(key);
sign.update(data.getBytes("UTF-8"));
return sign.verify(Base64.decode(signature.getBytes("UTF-8"), Base64.NO_WRAP));
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
in .NET public key is exported in xml format with following code:
public string ExportPublicToXML(string publicKey)
{
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(new CspParameters()
{
ProviderType = 1
});
csp.ImportCspBlob(Convert.FromBase64String(publicKey));
return csp.ToXmlString(false);
}
and then modulus and exponent are used in Android to load public key:
private RSAPublicKey GetPublicKey(String keyXmlString) throws InvalidKeySpecException, UnsupportedEncodingException, NoSuchAlgorithmException
{
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String modulusString = keyXmlString.substring(keyXmlString.indexOf("<Modulus>"), keyXmlString.indexOf("</Modulus>")).replace("<Modulus>", "");
String exponentString = keyXmlString.substring(keyXmlString.indexOf("<Exponent>"), keyXmlString.indexOf("</Exponent>")).replace("<Exponent>", "");
byte[] modulusBytes = Base64.decode(modulusString.getBytes("UTF-8"), Base64.DEFAULT);
byte[] dBytes = Base64.decode(exponentString.getBytes("UTF-8"), Base64.DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger d = new BigInteger(1, dBytes);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, d);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
I am trying to hash a value (SHA1) in both C# and Java, and then return a base64 representation. I get 2 different results.
I know this is because Java uses signed bytes while C# doesn't.
C# version :
static public string toSHA1(string toEncrypt)
{
return toSHA1(toEncrypt, new UTF8Encoding());
}
static public string toSHA1(string toEncrypt, Encoding encoding)
{
String salt = "fE4wd#u*d9b9kdKszgè02ep5à4qZa!éi6";
SHA256Managed sha256hasher = new SHA256Managed();
byte[] hashedDataBytes = sha256hasher.ComputeHash(encoding.GetBytes(toEncrypt + salt));
return Convert.ToBase64String(hashedDataBytes);
}
Java version :
public static String toSHA1(String toEncrypt) {
return toSHA1(toEncrypt, "UTF-8");
}
public static String toSHA1(String toEncrypt, String encoding) {
String salt = "fE4wd#u*d9b9kdKszgè02ep5à4qZa!éi6";
String res = null;
toEncrypt = toEncrypt + salt;
try {
byte[] dataBytes = toEncrypt.getBytes(encoding);
MessageDigest md = MessageDigest.getInstance("SHA-1");
res = Base64.encodeBytes(md.digest(dataBytes));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return res;
}
I can't manage to find a solution to get the correct base64 result using Java.
Converting signed values to unsigned ones forces the use of int data type, but as soon as I put it in a byte data type, I get my signed bytes back...
Base64.encodeBytes is waiting for a byte array, so is there any way I can pass an unsigned byte array to this method ? What can I do with that int array ? :
int[] dataInt = new int[dataBytes.length];
// signed to unsigned
for (int i=0; i<dataBytes.length; i++)
{
dataInt[i] = (dataBytes[i] & 0xFF);
}
I can't modify the C# version, I have to adapt the Java version to give the same results.
The problem is very simple... From your C# code:
SHA256Managed sha256hasher = new SHA256Managed()
SHA-256 != SHA-1. Use the SHA1 class instead in C#, or use SHA-256 in Java as well. As you apparently can't change the C# code, you should change the Java instead:
MessageDigest md = MessageDigest.getInstance("SHA-256");
Once you've done that, the base64-encoded data should be the same in both platforms. Even though bytes are signed in Java, base64 encoders treat them as unsigned... they're only interested in the bits, basically.
I'd also strongly suggest that you represent your salt in ASCII in the source code, using \uxxxx escaping for any non-ASCII characters. This will prevent problems due to compiling using the wrong encoding.
I'm having trouble with WS-Security, and creating a nonce and password digest that is correct.
I am successfully using SoapUI to send data to an Oracle system. So I'm able to intercept SoapUI's call (change proxy to 127.0.0.1 port 8888 to use Fiddler where it fails because it's over SSL) - intercepting is important because these values can only be used once. I can then grab the nonce, created timestamp and password digest put them into my code (I've only got 30 seconds to do this as the values don't last!) and I get a success.
So I know it's nothing else - just the Password Digest.
The values I use are the following:
Nonce: UIYifr1SPoNlrmmKGSVOug==
Created Timestamp: 2009-12-03T16:14:49Z
Password: test8
Required Password Digest: yf2yatQzoaNaC8BflCMatVch/B8=
I know the algorithm for creating the Digest is:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
using the following code (from Rick Strahl's post)
protected string GetSHA1String(string phrase)
{
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
return Convert.ToBase64String(hashedDataBytes);
}
I get:
GetSHA1String("UIYifr1SPoNlrmmKGSVOug==" + "2009-12-03T16:14:49Z" + "test8") = "YoQKI3ERlMDGEXHlztIelsgL50M="
I have tried various SHA1 methods, all return the same results (which is a good thing I guess!):
SHA1 sha1 = SHA1.Create();
SHA1 sha1 = SHA1Managed.Create();
// Bouncy Castle:
protected string GetSHA1usingBouncyCastle(string phrase)
{
IDigest digest = new Sha1Digest();
byte[] resBuf = new byte[digest.GetDigestSize()];
byte[] bytes = Encoding.UTF8.GetBytes(phrase);
digest.BlockUpdate(bytes, 0, bytes.Length);
digest.DoFinal(resBuf, 0);
return Convert.ToBase64String(resBuf);
}
Any ideas on how to get the correct hash?
The problem was the nonce.
I was trying to use a nonce that had already been Base64 encoded. If you want to use a Nonce that is in the form "UIYifr1SPoNlrmmKGSVOug==" then you need to decode it.
Convert.FromBase64String("UIYifr1SPoNlrmmKGSVOug==")
which is a byte array.
So we need a new method:
public string CreatePasswordDigest(byte[] nonce, string createdTime, string password)
{
// combine three byte arrays into one
byte[] time = Encoding.UTF8.GetBytes(createdTime);
byte[] pwd = Encoding.UTF8.GetBytes(password);
byte[] operand = new byte[nonce.Length + time.Length + pwd.Length];
Array.Copy(nonce, operand, nonce.Length);
Array.Copy(time, 0, operand, nonce.Length, time.Length);
Array.Copy(pwd, 0, operand, nonce.Length + time.Length, pwd.Length);
// create the hash
var sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(operand);
return Convert.ToBase64String(hashedDataBytes);
}
CreatePasswordDigest(Convert.FromBase64String("UIYifr1SPoNlrmmKGSVOug=="), "2009-12-03T16:14:49Z", "test8")
which returns yf2yatQzoaNaC8BflCMatVch/B8= as we want.
Remember to use the same createdTime in the digest as you put in the XML, this might sound obvious, but some people include milliseconds on their timestamps and some don't - it doesn't matter, it just needs to be consistent.
Also the Id field in the UsernameToken XML doesn't matter - it doesn't need to change.
Here's a method to create a Nonce like the one above, if you don't want to use GUIDs like Rick uses:
private byte[] CreateNonce()
{
var Rand = new RNGCryptoServiceProvider();
//make random octets
byte[] buf = new byte[0x10];
Rand.GetBytes(buf);
return buf;
}
I hope that helps someone - it took me lots of frustration, trial and error, searching web pages, and general head/wall banging.
I'm looking to convert some C# code to the equivalent in Java.
The C# code takes some string content, and a signature (generated using the private key, on a seperate machine) and combined with the public key it verifies the signature matches, providing a level of assurance that the request has not been tampered with.
public bool VerifySignature(string content, byte[] signatureBytes, AsymmetricAlgorithm publicKey)
{
var hash = new MD5CryptoServiceProvider();
byte[] dataBuffer = Encoding.ASCII.GetBytes(content);
var cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write);
cs.Write(dataBuffer, 0, dataBuffer.Length);
cs.Close();
var deformatter = new RSAPKCS1SignatureDeformatter(publicKey);
deformatter.SetHashAlgorithm("MD5");
return deformatter.VerifySignature(hash, signatureBytes);
}
The public key itself is an X509 Certificate - constructed from a .cer file, stored as assembly resource i.e.
byte[] data; // data is read from a resource stream.
var publicKey = new X509Certificate2(data, "", X509KeyStorageFlags.MachineKeySet).PublicKey.Key
What I'm looking to do is emulate this functionality in Java, so I can verify the signature generated by some code in C#... I've started investigating the crypto functionality of Java, but I'm a bit of a java noob. Here's what I've come up with so far:
byte[] certContents=null;
byte[] signature=null;
String contents = "abc";
// load cert
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certContents));
// grab public key
RSAPublicKey publicKey = (RSAPublicKey)cert.getPublicKey();
// get sha1 hash for contents
Mac mac = Mac.getInstance("HmacSHA1");
mac.update(contents.getBytes());
byte[] hash = mac.doFinal();
// get cipher
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// verify signature of contents matches signature passed to method somehow (and this is where I'm stuck)
Can anyone provide any insight into how I can verify the signature - or provide links to some resources which might explain the java.crypto and java.security.cert usage better then the run of the mill java docs.
That C# code looks really confusing to me. It use SHA1CryptoServiceProvider but uses MD5 hash so I can't tell which hashing algorithm it's using. I assume it's MD5.
The signature verification process involves padding so your code wouldn't work. Following is some snippet from my code and you can use it to verify the signature. data is the bytes to sign and sigBytes holds the signature.
String algorithm = "MD5withRSA";
// Initialize JCE provider
Signature verifier = Signature.getInstance(algorithm);
// Do the verification
boolean result=false;
try {
verifier.initVerify(cert); // This one checks key usage in the cert
verifier.update(data);
result = verifier.verify(sigBytes);
}
catch (Exception e) {
throw new VerificationException("Verification error: "+e, e);
}