Translating C# RSACryptoServiceProvider into JAVA Code - c#

I was given this C# code written by the web service team that exposes some web service that I'm planning to consume. My password needs to be encrypted with this code so that the web service knows how to decrypt it on their end.
using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(publicKey);
byte[] plainBytes = Encoding.Unicode.GetBytes(clearText);
byte[] encryptedBytes = rsa.Encrypt(plainBytes, false);
return Convert.ToBase64String(encryptedBytes);
}
I'm using Java to consume this web service and right now, I'm having problem translating that #C code into Java code because that web service can't decrypt my password properly.
Here's my current failed attempt:-
// my clear text password
String clearTextPassword = "XXXXX";
// these values are provided by the web service team
String modulusString = "...";
String publicExponentString = "...";
BigInteger modulus = new BigInteger(1, Base64.decodeBase64(modulusString.getBytes("UTF-8")));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(publicExponentString.getBytes("UTF-8")));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String encodedEncryptedPassword = new String(Base64.encodeBase64(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));
What did I do wrong? Thanks much.
2013-08-07 - UPDATE
I was reading this website and I realized that my modulus value and public exponent value are not in Hex. So, I modified my code a little bit and tried with RSA/ECB/PKCS1PADDING as mentioned by #Dev.
// my clear text password
String clearTextPassword = "XXXXX";
// these are the actual values I get from the web service team
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";
Base64 base64Encoder = new Base64();
String modulusHex = new String(Hex.encodeHex(modulusString.getBytes("UTF-8")));
String publicExponentHex = new String(Hex.encodeHex(publicExponentString.getBytes("UTF-8")));
BigInteger modulus = new BigInteger(modulusHex, 16);
BigInteger publicExponent = new BigInteger(publicExponentHex);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String encodedEncryptedPassword = new String(base64Encoder.encode(cipher.doFinal(clearTextPassword.getBytes("UTF-8"))));
When I hit the webservice, I'm getting this error: "The data to be decrypted exceeds the maximum for this modulus of 128 bytes." It seems like the clear text password is still not encrypted properly.
Any help or suggestion is greatly appreciated. Thanks.
2013-08-09 - SOLUTION
I posted my final working solution below.

Found the solution.
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";
byte[] modulusBytes = Base64.decodeBase64(modulusString);
byte[] exponentBytes = Base64.decodeBase64(publicExponentString);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = clearTextPassword.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.encodeBase64String(cipherData);

According to MSDN docs on RSACryptoServiceProvider.Encrypt, when the second argument is false the cipher uses PKCS#1 v1.5 padding. So right off the bat your cipher spec is incorrect.
Try RSA/ECB/PKCS1PADDING instead.
You are converting your key material to much in your second code example and you corrupted it which ends up making your cipher think you have more key material than you actually have and makes your message too long (which is triggering your error) as well as unintelligible to the decryption cipher on the other end. Convert directly to byte arrays and pass those to BigInteger.
String modulusString = "...";
String publicExponentString = "...";
byte[] mod = Base64.decodeBase64(modulusString);
byte[] e = Base64.decodeBase64(publicExponentString);
BigInteger modulus = new BigInteger(1, mod);
BigInteger publicExponent = new BigInteger(1, e);

Using RSA/ECB/OAEPWithSHA-1AndMGF1Padding seems to be the solution for this issue.
Don't forget these replacements.
Encoding to Base64
Use System.Convert to convert the input to Base64.
Replace + by - and / by _. Example: Foo+bar/=== becomes Foo-bar_===.
Replace any number of = at the end of the string, with an integer denoting how many they were. Example: Foo-bar_=== becomes Foo-bar_3.
Decoding from Base64
Replace the digit at the end of the string by the same number of = signs. Example: Foo-bar_3 becomes Foo-bar_===.
Replace - by + and _ by /. Example: Foo-bar_=== becomes Foo+bar/===.
Use System.Convert to decode the preprocessed input from Base64.

Related

Generate RSA KEY paramater from secret key without using bouncy castle or any third party library

I want to get the RSAKey Parameters in order to validate JWT token i.e. without using bouncy castle or any third party library.I search a lot but unable to find any thing that generate Modulus and Exponent i.e. part of RSAParameters.
Below sharing small snippet i have tried please let me know if you have any suggestions
string secret = "XXXXXXX";
string token = "XXXXXXX";
string[] parts = token.Split('.');
string header = parts[0];
string payload = parts[1];
var keyBytes = Convert.FromBase64String(secret); // your key here
var rsaKeyParameters = (RsaKeyParameters)PublicKeyFactory.CreateKey(keyBytes);//////I don't want to use this line of code as it is part of //////////third party library it only helps us in getting modulus and exponent
//////Please let me know any other way to achieve validation of JWT token if any
RSAParameters rsaParameters = new RSAParameters
{
Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
};
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
byte[] hash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(header + '.' + payload));
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
bool isv = rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2]));
Console.WriteLine("is" + isv);

How to convert php's mb_convert_encoding() to C# equivalent

I have tried rather unsuccessfully , to convert the following php code to C#
and require help please.
php code is
$string="012014Te$ting#501834502014060007400";
$salt = "Cli3ntH#sah";
$utfString=mb_convert_encoding($string.$salt,ÄSCII");
$hashTag=sha1($utfString,true);
$Hash = base64_encode($hashTag);
with C# code
byte[] ascii = Encoding.ASCII.GetBytes(objtohash);
byte[] utf8 = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, ascii);
byte[] hashBytes2 = sha1.ComputeHash(utf8);
var Hash = Convert.ToBase64String(hashBytes2);
also tried this, where objtohash = $string.$salt (i.e. concatenated)
var sha1 = new System.Security.Cryptography.SHA1Managed();
//convert to ascii byte array
byte[] AScii = EncodeAscii(objtohash);
//Hash it
byte[] hashBytes = sha1.ComputeHash(AScii);
//convert it to base 64
var Hash = Convert.ToBase64String(hashBytes);
I have tried several other ways as per SO, but I cannot get the same hashed value as the php sample.Hopefully someone can do it and hopefully give explanation as to why.
Thanks
The syntax error was finger trouble.
The answer it turns out, ..basically by trying any and all combinations of what i could find by googling is:
var objtohashArry = Encoding.ASCII.GetBytes(objtohash);
var HashSharresult = SHA1.Create().ComputeHash(objtohashArry);
var requestHash = Convert.ToBase64String(HashSharresult);
RequestHash = requestHash;

Blowfish ECB encryption in C# implementation

I have a client who needs us to use Blowfish ECB encryption with cipherMode 0, output 1. I have tried to solve for this, but I'm getting stuck. How do I fix my code?
Here are the full client instructions:
Algorithm: Blowfish
・ Mode: ECB
・ Padding: PKCS5Padding
*Initial vector is unnecessary because we use ECB mode.
Example
・Encrypt Key: 2fs5uhnjcnpxcpg9
 → Plain Text : 3280:99:20120201123050
 → Cipher Text : daa745f1901364c0bd42b9658db3db96336758cd34b2a576
* Please keep Cipher Text with 16 hexadecimal characters .
* Please generate Cipher Text without “salt”.
I need to write this in C#. Here's what I did, but it doesn't seem to be working:
string member_id = "3280";
string panelType = "99";
string RandomString = "20120201123050";
string encryptionKey = "2fs5uhnjcnpxcpg9";
string cryptstr = member_id + ":" + panelType + ":" + RandomString;
string plainText = cryptstr;
BlowFish b = new BlowFish(encryptionKey);
string cipherText = b.Encrypt_ECB("3280:99:20120201123050");
The result is not daa745f1901364c0bd42b9658db3db96336758cd34b2a576. Where did I go wrong?
Encrypt_ECB() so I assume its Schneier's class.
The ctor expects a hexadecimal string if one is passed, you need the overload for a byte array:
BlowFish b = new BlowFish(Encoding.UTF8.GetBytes(encryptionKey));
The output is still not correct, lets see what it really should be by decrypting their example:
string clear = b.Decrypt_ECB("daa745f1901364c0bd42b9658db3db96336758cd34b2a576");
gives us:
"3280:99:20120201123050\u0002\u0002"
Which is good but there are 2 0x2 bytes on the end, the N x 0xN is due to the PKCS padding. To get the match you need to pad the input:
// input to bytes
List<byte> clearBytes = new List<byte>(Encoding.UTF8.GetBytes("3280:99:20120201123050"));
// how many padding bytes?
int needPaddingBytes = 8 - (clearBytes.Count % 8);
// add them
clearBytes.AddRange(Enumerable.Repeat((byte)needPaddingBytes, needPaddingBytes));
// encrypt
byte[] cipherText = b.Encrypt_ECB(clearBytes.ToArray());
// to hex
string cipherTextHex = BitConverter.ToString(cipherText).Replace("-", "").ToLowerInvariant();

How to transmit an AES encryption key?

On my Blackberry I am creating an AES key and encrypting data. I am then encrypting the AES key with RSA before sending to the client c#.net
The AES key is a byte array. How can I convert this to a string so that it can be encrypted by RSA and then decrypted on the .net side?
Do I have to convert to string?
I am transmitting the data via JSON. I guess my question is really how to transmit a but array in JSON? What character encoding would I use?
Thanks.
You can use the following, which is URL safe and relatively easy to visually inspect. This takes a little more storage than Convert.ToBase64String, but shouldn't be an issue with a fixed width encryption key.
string MyKey = BitConverter.ToString(MyAESKey); // dash removal is trivial here
OR
string MyKey = Convert.ToBase64String(MyAESKey);
Code Sample
byte[] a = new byte[256/8];
Random random = new Random();
random.NextBytes(a);
string base64 = Convert.ToBase64String(a);
byte [] b = Convert.FromBase64String(base64);
if (a.SequenceEqual(b))
// true
string c = BitConverter.ToString(a);
string[] c1 = c.Split('-');
byte[] d = new byte[arr.Length];
for (int i = 0; i < arr.Length; i++) d[i] = Convert.ToByte(c1[i], 16);
if (a.SequenceEqual(d))
// true

Bouncy Castle, RSA: transforming keys into a String format

I'm using RSA (Bouncy Castle API) in my C# project. I generated the keypair with this method:
RsaKeyPairGenerator r = new RsaKeyPairGenerator();
r.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
AsymmetricKeyParameter private_key = keys.Private;
AsymmetricKeyParameter public_key = keys.Public;
Now I want to save them in a txt file but the problem is that I can't convert them to a string format. I read in another post that keys must be serialized using:
PrivateKeyInfo k = PrivateKeyInfoFactory.CreatePrivateKeyInfo(private_key);
byte[] serializedKey = k.ToAsn1Object().GetDerEncoded();
Is it the right way? If yes, what should I do after this? Just convert them from byte[] to String?
You could also use PemWriter to store them in PEM format:
TextWriter textWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(keys.Private);
pemWriter.Writer.Flush();
string privateKey = textWriter.ToString();
Now privateKey contain something like this:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDFhB3xI1AzSMsKvt7rZ7gp2o/vd49zON89iL1ENvKkph7oFXa2
ew/hjzbAV33lHnFFlA/vA5SDCbggRyU1/SmjfuPJFEzFbgcPLuO1Sw6z+bWXiIFp
QNCOTIw11c0fbwk+kB2y4E1OkLv5f9atlNlekb4wBn8bMbFYtu6LGWjkFQIDAQAB
AoGANPoMteLM3hSGMSmkzOsS4Fb5CDe/SB5W8kA805ERX8wWuhUXtDYpukwZWVme
MNgLdagS5f7F1KfEtROgDW0Lv4/T/FWAbpgh8O2CPKYDY4ZXl8tmRH9dtYn/824l
veLxdgNjHwo5OMvuTSDMjC3tbg2UA3kmV4VAm5QotlRinUECQQDo4zvI5e81zWnS
kNrUARX80t432MOZyr0RvAaVJfBNQpJl0H0xp5LKP74hvPVO9WdJvJ0M4Z4QrmGO
bm2Hsfz5AkEA2R469YXxgPLDg/LvUQqfrl8Ji9+rip7eQP7iS/dt66NMS31/HymT
+HscEZ3qGlnQuyyyRR2rGQdhdjU42HNy/QJBAKbPTF1DxSmGbovyUauU84jaCW17
B++6dd6kDRr7x7mvO2lOAr50RwIy0h8cV6EsycTZIqy9VhigryP0GOQfKxECQA8T
uVZpab7hnNAh45qGGVabhOcwrhHfPGHZEU/jK7/sRBUN7vD0CzF7IxTaGXKhAAyv
auW/zKzdRVhXE858HeUCQQCGaaAg8GwM0qIS0nHRTLldu4hIGjKn7Sk0Z46Plfwr
oqPCtuP4ehX85EIhqCcoFnG6Ttr6AxSgNMZvErVxDBiD
-----END RSA PRIVATE KEY-----
Well, I don't know about the RSA-specific side, but once you've got an opaque binary string (i.e. it could contain any arbitrary data) the best bet for text conversion is Convert.ToBase64String(byte[]) which you can reverse with Convert.FromBase64String(string).
Do not use Encoding.GetString(byte[]) and Encoding.GetBytes(string) for this - the binary data isn't text in a particular encoding, and shouldn't be treated as such. You're almost bound to lose data if you try this.
This might be what you are looking out for:
http://www.rahulsingla.com/blog/2011/04/serializing-deserializing-rsa-public-private-keys-generated-using-bounty-castle-library
Try the following
RsaKeyPairGenerator rsaKeyPairGenerator = new RsaKeyPairGenerator();
rsaKeyPairGenerator.Init(new KeyGenerationParameters(new SecureRandom(), XXX));
AsymmetricCipherKeyPair keys = rsaKeyPairGenerator.GenerateKeyPair();
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keys.Private);
// Write out an RSA private key with it's asscociated information as described in PKCS8.
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded();
// Convert to Base64 ..
string serializedPrivateString = Convert.ToBase64String(serializedPrivateBytes);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keys.Public);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
string serializedPublicString = Convert.ToBase64String(serializedPublicBytes);
If you convert the bouncycastle certificate to a .net certificate. The function to do this is in the bouncycastle lib (i believe it's in a class called DotNetUtilities). The RSACryptoServiceProvider has a function:
ToXmlString(bool includePrivateKey).
Which gives you an x representation of a certificate with if you want the private key containing all the components serialized to base64 seperately, exponent, modulus, and d (private exponent).

Categories

Resources