Custom Single Sign-On Using BouncyCastle with Microsoft Self Signed Certificate
Need to create a Single Sign-on PKI infrastructure between Microsoft and Java? Recently, we had a requirement to process single sign on requests over https. The project called for integration of our Java end with client’s Microsoft based SSO (single sign on) end. The username/password was stored in Active Directory and we have a database of users without passwords. Here are some key points in the process:
1) Client sent over a Microsft self signed chained certificate in which I was not able to import into a Java keystore file. So, I imported into Internet Explorer then exported to a .cer file. Then, I was able to import into java keystore.
2) I sent the dev environment public key (using Java keytool) to client. Client uses it to send two strings via Form POST over https. (I’ll post the C# code if anyone is interested)
3) Both Strings are used for PKI Signature verfication. Here’s how to do it using BouncyCastle:
private boolean verify (String encryptedMessage, String encodedSignuture) {
Keystore keystore;
String alias = “root”;
try {
FileInputStream file_is = new FileInputStream(keystorefile);
keyStore = Keystore.getInstance(”JCEKS”);
keystore.load(file_is, password.toCharArray());
Certificate cert = keyStore.getCertificate(alias);
Signature sig = Signature.getInstance(”SHA1withRSA”);
sig.initVerify(cert.getPublicKey());
sig.update(Base64.decode(encryptedMessage.getBytes()));
return sig.verify(Base64.decode(encodedSignature.getBytes()));
} catch (Exception e) {
//log
}
}
Thank you to BouncyCastle for making Signature verifcation straightforward. We were able to implement a custom single sign-on solution between Microsoft and Java. Thank you to David Hook of the BouncyCastle project and his book “Beginning Cryptography with Java”.
If you know of other single sign-on solutions and/or products, please post a comment or trackback to this post.






























I saw your posting and we are doing just the reverse. We will receiv encrypted token over web created using BouncyCastle API for Java and now we have decrypt it over our end using C#.
I am looking into documentation and get some hints but not sure what exactly should be done.
Any help would be great to point me in the right direction or any resource.
Thanks
Comment by Neeraj Singh — September 14, 2006 @ 11:53 pm
Neeraj-
Here’s some sample code in C# that might help you out-
using System;
using System.IO;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using Microsoft.Web.Services;
using Microsoft.Web.Services.Security;
using Microsoft.Web.Services.Security.X509;
namespace Example.Enterprise.Security.Applications.SingleSignon
{
public class RSAHelper
{
public RSAHelper()
{
}
public Microsoft.Web.Services.Security.X509.X509Certificate GetCertificateByName(string CertificateCName)
{
Microsoft.Web.Services.Security.X509.X509Certificate certificate1;
X509CertificateStore store1 = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore);
store1.OpenRead();
Microsoft.Web.Services.Security.X509.X509CertificateCollection collection1 = store1.FindCertificateBySubjectString(CertificateCName);
if (collection1.Count == 0)
{
certificate1 = null;
}
else
{
certificate1 = collection1[0];
}
store1.Close();
return certificate1;
}
public string sEncrypt(string clearText, string certificateCName)
{
Microsoft.Web.Services.Security.X509.X509Certificate certificate1 = GetCertificateByName(certificateCName);
RSAParameters parameters1 = certificate1.PublicKey.ExportParameters(false);
CspParameters parameters2 = new CspParameters();
parameters2.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(parameters2);
provider1.ImportParameters(parameters1);
byte[] buffer1 = Encoding.UTF8.GetBytes(clearText);
byte[] buffer2 = provider1.Encrypt(buffer1, false);
return Convert.ToBase64String(buffer2);
}
public string Sign(string dataToSign, string certificateCName)
{
Microsoft.Web.Services.Security.X509.X509Certificate certificate1 = this.GetCertificateByName(certificateCName);
RSAParameters parameters1 = certificate1.Key.ExportParameters(true);
CspParameters parameters2 = new CspParameters();
parameters2.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(parameters2);
provider1.ImportParameters(parameters1);
byte[] buffer1 = Convert.FromBase64String(dataToSign);
byte[] buffer2 = provider1.SignData(buffer1, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(buffer2);
}
public string sDecrypt(string encryptedText, string certificateCName)
{
Microsoft.Web.Services.Security.X509.X509Certificate certificate1 = GetCertificateByName(certificateCName);
RSAParameters parameters1 = certificate1.Key.ExportParameters(true);
CspParameters parameters2 = new CspParameters();
parameters2.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(parameters2);
provider1.ImportParameters(parameters1);
byte[] buffer1 = Convert.FromBase64String(encryptedText);
byte[] buffer2 = provider1.Decrypt(buffer1, false);
ASCIIEncoding ascii = new ASCIIEncoding();
return ascii.GetString(buffer2);
}
public string VerifySign(string encryptedText, string signature, string certificateCName)
{
Microsoft.Web.Services.Security.X509.X509Certificate certificate1 = this.GetCertificateByName(certificateCName);
RSAParameters parameters1 = certificate1.PublicKey.ExportParameters(false);
CspParameters parameters2 = new CspParameters();
parameters2.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(parameters2);
provider1.ImportParameters(parameters1);
byte[] buffer1 = Convert.FromBase64String(encryptedText);
byte[] buffer2 = Convert.FromBase64String(signature);
bool samesig = provider1.VerifyData(buffer1, new SHA1CryptoServiceProvider(),buffer2);
return samesig.ToString();
}
}
}
Comment by mcgrath — September 15, 2006 @ 8:37 am
Hi Todd,
I am new to this Asymmetric Encryption using RSA. Actually one of our vendor need SSO via passing encrypted data to authenticate using BouncyCastle API for Java.
They are using our Public Key(generate using keytool) and their Private Key to sign. Both keys are 1024 bits RSA Algo.
At our end we use .NET with C# and now I want to use BouncyCastle API for C# to decrypt the data using our Private Key and verify the signature using their Public Key.
Questions:
1) How our C# code can access the our Private Key generate using Keytool utility which supposed to be in JKS?
2) Where should I import the Vendor’s Public Key to be accessible from C#?
3) How can I use BouncyCastle API to do that?
Can you give me some direction or point me to some resources which can guide me? I looked into BouncyCastle C# mailing list, documentation and looked almost everywhere on google like
http://www.jensign.com/JavaScience/dotnet/RSAEncrypt/index.html
http://www.codeproject.com/dotnet/SimpleEncryption.asp?df=100&forumid=172899&exp=0&select=1434169
We are using .NET 1.1 and upgrade to 2.0 is not in picture.
Thanks for any help.
Neeraj
Comment by Neeraj Singh — September 19, 2006 @ 5:08 pm