GetToken Helper for Cardspace on .NET 2.0

Many people have asked how we can retrieve and process a token sent by a subject or a Security Token Service. Just to showcase the non-intrusiveness of _WCS_, in that we can easily incorporate a Cardspace "Sign-in with Cardspace" into your website today such as this or this, I have shown snippets of how we can do so via php here.

As an another example of non-intrusiveness, I have also got a simple working sample that you can use to integrate into your ASP.NET 2.0 page today.

Of course, this is a hack job and there are no try catch and the xml parsing code is hastily done. To summarize, I wont win the elegance award here  ... but you can get it to work on .NET 2.0 (or maybe even 1.1) i-wink ...

Of course, this is a hack job and there are no try catch and the xml parsing code is hastily done. To summarize, I wont win the elegance award here  ... but you can get it to work on .NET 2.0 (or maybe even 1.1) ...

    [BEGIN]
    'This will get you your encrypted token
    Dim str As Stream
    str = Request.InputStream
    Dim sr As New StreamReader(str)
    Dim s As String = sr.ReadToEnd
    s = Server.HtmlDecode(Server.UrlDecode(s))

    'the stream will be ASCII encoded
    Dim u8 As System.Text.UTF8Encoding = New System.Text.UTF8Encoding

    Dim fs As New FileStream("C:\temp\CardspaceXMLToken.xml", FileMode.Create)
    'Remove the "xmlToken="
    Dim i As Integer = s.IndexOf("<")
    s = s.Substring(i)
    fs.Write(u8.GetBytes(s), 0, u8.GetBytes(s).Length)
    fs.Flush()
    fs.Close()
    '--------------------------------
    'The will decrypt that request token and return a Signed Security SAML Token
    Dim encryptedDoc As New XmlDocument()
    encryptedDoc.Load("C:\temp\CardspaceXMLToken.xml")

    'Check for <EncryptedData> element
    If encryptedDoc.GetElementsByTagName _
    ("EncryptedData", "
http://www.w3.org/2001/04/xmlenc#").Count = 0 Then Return

    Dim encryptedD As XmlElement = CType(encryptedDoc.GetElementsByTagName _
    ("EncryptedData", "
http://www.w3.org/2001/04/xmlenc#")(0), XmlElement)

    'Check for @Algorithm attribute and make sure its http://www.w3.org/2001/04/xmlenc#aes256-cbc
    If encryptedD.ChildNodes(0).Attributes("Algorithm") Is Nothing Or _
    encryptedD.ChildNodes(0).Attributes("Algorithm").Value <> _
    "
http://www.w3.org/2001/04/xmlenc#aes256-cbc" Then Return

    Dim a As New RijndaelManaged

    'Check for <KeyInfo> element
    If encryptedD.ChildNodes(1).Name <> "KeyInfo" Then Return

    'Check for <EncryptionMethod> element
    Dim encryptedM As XmlElement = CType(encryptedDoc.GetElementsByTagName _
    ("EncryptionMethod", "
http://www.w3.org/2001/04/xmlenc#")(1), XmlElement)

    'Check for @Algorithm attribute and make sure its http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p
    If encryptedM.Attributes("Algorithm") Is Nothing Or _
    encryptedM.Attributes("Algorithm").Value <> _
    "
http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" Then Return

    'Check for <CipherData\CipherValue>
    If encryptedD.GetElementsByTagName("CipherValue", _
    "
http://www.w3.org/2001/04/xmlenc#").Count = 0 Then Return

    'Retrieving the Encrypted Symmetric Key and the Security Token
    Dim e_SymmKey As String = encryptedDoc.GetElementsByTagName _
    ("CipherValue", "
http://www.w3.org/2001/04/xmlenc#")(0).InnerText
    Dim e_SecurityToken As String = encryptedDoc.GetElementsByTagName _
    ("CipherValue", "
http://www.w3.org/2001/04/xmlenc#")(1).InnerText

    Dim rsaCsp As New RSACryptoServiceProvider
    Dim privatecert As New X509Certificates.X509Certificate2
    privatecert.Import("Softwaremaker.NET.SSL.pfx", "Softwaremaker_NET_SSL_pfx_password",     X509Certificates.X509KeyStorageFlags.Exportable)
    rsaCsp.FromXmlString(privatecert.PrivateKey.ToXmlString(True))

    'Now we have the Symmetric Key
    Dim DecryptedStrAsByt() As Byte = _
    rsaCsp.Decrypt(System.Convert.FromBase64String(e_SymmKey), True)

    'Moving on to use the Symmetric Key to decrypt Token
    Dim rijndaelM As New RijndaelManaged
    rijndaelM.Mode = CipherMode.CBC

    Dim swmDecryptor As ICryptoTransform
    swmDecryptor = rijndaelM.CreateDecryptor(DecryptedStrAsByt, Nothing)

    'Define memory stream which will be used to hold encrypted data.
    Dim cipherTextBytes As Byte()
    cipherTextBytes = System.Convert.FromBase64String(e_SecurityToken)

    Dim memoryStream As MemoryStream
    memoryStream = New MemoryStream(cipherTextBytes)

    ' Define memory stream which will be used to hold encrypted data.
    Dim cryptoStream As CryptoStream
    cryptoStream = New CryptoStream(memoryStream, swmDecryptor, CryptoStreamMode.Read)

    ' Since at this point we don't know what the size of decrypted data
    ' will be, allocate the buffer long enough to hold ciphertext;
    ' plaintext is never longer than ciphertext.
    Dim plainTextBytes As Byte()
    ReDim plainTextBytes(cipherTextBytes.Length)

    ' Start decrypting.
    Dim decryptedByteCount As Integer
    decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)

    ' Close both streams.
    memoryStream.Close()
    cryptoStream.Close()

    ' Convert decrypted data into a string.
    ' Let us assume that the original plaintext string was UTF8-encoded.
    Dim plainTextToken As String
    plainTextToken = System.Text.Encoding.UTF8.GetString(plainTextBytes, 16, _
                                        decryptedByteCount - 16)

    return plainTextToken
    [END]
    '--------------------------------

Of course, you would have to verify the signed token yourself BUT this decryption process is definitely a step in the right direction

If you have benefitted from these sample snippets, maybe you can pay-it-forward by implementing and then sharing the signature-verification codes with me here? I am too lazy ... i-smile.

 

Published Friday, August 11, 2006 12:14 PM by Softwaremaker