Playing with the DDI Character Builder API
24 January 2011 in Articles by Iain M NormanFor anyone who’s been playing with the two new web-services that the online version of WotC’s Character Builder uses, you may have tried remotely logging in, but wondered how the password needs to be encrypted?
Well I’ve cracked the way passwords are encrypted and have been able to login remotely and do simple actions such as, get a list of all my characters and export the XML for an old style DnD4e file.
Here’s a simple bit of C# showing how to encode a password.
public static byte[] SimpleEncrypt(string value, string key)
{
byte[] buffer2;
ICryptoTransform transform = GetSimpleAlgorithm(key).CreateEncryptor();
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
stream2.Write(bytes, 0, bytes.Length);
stream2.Flush();
stream2.FlushFinalBlock();
stream.Position = 0L;
buffer2 = stream.ToArray();
}
}
return buffer2;
}
private static SymmetricAlgorithm GetSimpleAlgorithm(string key)
{
AesManaged aes = new AesManaged();
byte[] source = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(key));
return new AesManaged { Key = source, IV = source.Take<byte>((aes.BlockSize / 8)).ToArray<byte>() };
}
As you can see this takes the username and password as inputs, if you’ve built a nice client wrapper around the SOAP webservice, something that Visual Studio does for me, then logging in is as simple as calling the login method on either of the web services.
contentClient.Login(username, SimpleEncrypt(password, username));
If we then use the GetAvailableContent() method of the ContentVault service, we can return and enumerate a list of characters.
ContentInfo[] content = contentClient.GetAvailableContent(0);
for (int i = 0; i < content.Length; i++)
{
XDocument doc = XDocument.Parse(content[i].CommittedContent.Details.ToString());
var name = doc.Element("CharacterDetails").Element("Name").Value;
Console.WriteLine("{0} : {1}", i, name);
}
Then using the GetData() method of the same service we can grab the DnD4e XML file.
DataWithVersion data = contentClient.GetData(
new ContentVault.ContentIdentifier { ContentID = content[0].CommittedContent.Identifier.ContentID },
null
);
RawContentBlob blob = data.Data as RawContentBlob;
String charFile = new UTF8Encoding().GetString(blob.RawData, 0, blob.RawData.Length);
File.WriteAllBytes("d:\\temp.dnd4e", blob.RawData);
There you go just a brief window into some of the things the ContentVault service can do.
No word from WotC on whether or not we’re allowed to do this though. I did ask, but never got a response.
One last note, if you’re doing this in Visual Studio then make sure the bindings for the web services have allowCookies set to true, then the login will be remembered for the subsequent calls to the service.
If you’re consuming the SOAP in some other not Microsoft way, then obviously you’ll need to do the same thing, save the cookie from the login response and send it on with any following requests.
Comments: 37 comments

